From e8a389a2d60b6ff53118a05f72c266fc3bd725b0 Mon Sep 17 00:00:00 2001 From: Karl Berry Date: Mon, 16 Apr 2012 23:15:11 +0000 Subject: fontools (6mar12) git-svn-id: svn://tug.org/texlive/trunk@25995 c570f23f-e606-0410-a88d-b1316a301751 --- .../texk/texlive/linked_scripts/fontools/afm2afm | 458 +- .../texk/texlive/linked_scripts/fontools/autoinst | 2267 +++++---- .../texk/texlive/linked_scripts/fontools/cmap2enc | 5307 -------------------- .../texk/texlive/linked_scripts/fontools/font2afm | 190 - .../texk/texlive/linked_scripts/fontools/ot2kpx | 1102 ++-- .../texk/texlive/linked_scripts/fontools/pfm2kpx | 299 -- .../texlive/linked_scripts/fontools/showglyphs | 184 - Master/bin/alpha-linux/cmap2enc | 1 - Master/bin/alpha-linux/font2afm | 1 - Master/bin/alpha-linux/pfm2kpx | 1 - Master/bin/alpha-linux/showglyphs | 1 - Master/bin/amd64-freebsd/cmap2enc | 1 - Master/bin/amd64-freebsd/font2afm | 1 - Master/bin/amd64-freebsd/pfm2kpx | 1 - Master/bin/amd64-freebsd/showglyphs | 1 - Master/bin/amd64-kfreebsd/cmap2enc | 1 - Master/bin/amd64-kfreebsd/font2afm | 1 - Master/bin/amd64-kfreebsd/pfm2kpx | 1 - Master/bin/amd64-kfreebsd/showglyphs | 1 - Master/bin/i386-cygwin/cmap2enc | 1 - Master/bin/i386-cygwin/font2afm | 1 - Master/bin/i386-cygwin/pfm2kpx | 1 - Master/bin/i386-cygwin/showglyphs | 1 - Master/bin/i386-freebsd/cmap2enc | 1 - Master/bin/i386-freebsd/font2afm | 1 - Master/bin/i386-freebsd/pfm2kpx | 1 - Master/bin/i386-freebsd/showglyphs | 1 - Master/bin/i386-kfreebsd/cmap2enc | 1 - Master/bin/i386-kfreebsd/font2afm | 1 - Master/bin/i386-kfreebsd/pfm2kpx | 1 - Master/bin/i386-kfreebsd/showglyphs | 1 - Master/bin/i386-linux/cmap2enc | 1 - Master/bin/i386-linux/font2afm | 1 - Master/bin/i386-linux/pfm2kpx | 1 - Master/bin/i386-linux/showglyphs | 1 - Master/bin/i386-netbsd/cmap2enc | 1 - Master/bin/i386-netbsd/font2afm | 1 - Master/bin/i386-netbsd/pfm2kpx | 1 - Master/bin/i386-netbsd/showglyphs | 1 - Master/bin/i386-solaris/cmap2enc | 1 - Master/bin/i386-solaris/font2afm | 1 - Master/bin/i386-solaris/pfm2kpx | 1 - Master/bin/i386-solaris/showglyphs | 1 - Master/bin/mips-irix/cmap2enc | 1 - Master/bin/mips-irix/font2afm | 1 - Master/bin/mips-irix/pfm2kpx | 1 - Master/bin/mips-irix/showglyphs | 1 - Master/bin/powerpc-aix/cmap2enc | 1 - Master/bin/powerpc-aix/font2afm | 1 - Master/bin/powerpc-aix/pfm2kpx | 1 - Master/bin/powerpc-aix/showglyphs | 1 - Master/bin/powerpc-linux/cmap2enc | 1 - Master/bin/powerpc-linux/font2afm | 1 - Master/bin/powerpc-linux/pfm2kpx | 1 - Master/bin/powerpc-linux/showglyphs | 1 - Master/bin/sparc-linux/cmap2enc | 1 - Master/bin/sparc-linux/font2afm | 1 - Master/bin/sparc-linux/pfm2kpx | 1 - Master/bin/sparc-linux/showglyphs | 1 - Master/bin/sparc-solaris/cmap2enc | 1 - Master/bin/sparc-solaris/font2afm | 1 - Master/bin/sparc-solaris/pfm2kpx | 1 - Master/bin/sparc-solaris/showglyphs | 1 - Master/bin/universal-darwin/cmap2enc | 1 - Master/bin/universal-darwin/font2afm | 1 - Master/bin/universal-darwin/pfm2kpx | 1 - Master/bin/universal-darwin/showglyphs | 1 - Master/bin/win32/cmap2enc.exe | Bin 1536 -> 0 bytes Master/bin/win32/font2afm.exe | Bin 1536 -> 0 bytes Master/bin/win32/pfm2kpx.exe | Bin 1536 -> 0 bytes Master/bin/win32/showglyphs.exe | Bin 1536 -> 0 bytes Master/bin/x86_64-darwin/cmap2enc | 1 - Master/bin/x86_64-darwin/font2afm | 1 - Master/bin/x86_64-darwin/pfm2kpx | 1 - Master/bin/x86_64-darwin/showglyphs | 1 - Master/bin/x86_64-linux/cmap2enc | 1 - Master/bin/x86_64-linux/font2afm | 1 - Master/bin/x86_64-linux/pfm2kpx | 1 - Master/bin/x86_64-linux/showglyphs | 1 - Master/bin/x86_64-solaris/cmap2enc | 1 - Master/bin/x86_64-solaris/font2afm | 1 - Master/bin/x86_64-solaris/pfm2kpx | 1 - Master/bin/x86_64-solaris/showglyphs | 1 - Master/texmf-dist/doc/support/fontools/README | 96 +- .../support/fontools/examples/berling/berling.sty | 11 - .../support/fontools/examples/berling/berling.sub | 10 - .../support/fontools/examples/berling/makeberling | 70 - .../support/fontools/examples/berling/mbr_fnst.tex | 62 - .../fontools/examples/frutiger/frutiger.sty | 12 - .../fontools/examples/frutiger/frutiger.sub | 10 - .../fontools/examples/frutiger/lfr_fnst.tex | 68 - .../fontools/examples/frutiger/makefrutiger | 70 - .../fontools/examples/palatinox/Palatino_fnst.tex | 166 - .../fontools/examples/palatinox/make_Palatino | 92 - .../support/fontools/examples/palatinox/pala.sub | 4 - .../fontools/examples/palatinox/palatinox.sty | 36 - .../fontools/examples/palatinox/unsetSCaps.mtx | 32 - Master/texmf-dist/scripts/fontools/afm2afm | 458 +- Master/texmf-dist/scripts/fontools/autoinst | 2267 +++++---- Master/texmf-dist/scripts/fontools/cmap2enc | 5307 -------------------- Master/texmf-dist/scripts/fontools/font2afm | 190 - Master/texmf-dist/scripts/fontools/ot2kpx | 1102 ++-- Master/texmf-dist/scripts/fontools/pfm2kpx | 299 -- Master/texmf-dist/scripts/fontools/showglyphs | 184 - Master/texmf/doc/man/man1/afm2afm.1 | 185 +- Master/texmf/doc/man/man1/afm2afm.man1.pdf | Bin 5765 -> 5398 bytes Master/texmf/doc/man/man1/autoinst.1 | 629 +-- Master/texmf/doc/man/man1/autoinst.man1.pdf | Bin 25069 -> 29341 bytes Master/texmf/doc/man/man1/cmap2enc.1 | 450 -- Master/texmf/doc/man/man1/cmap2enc.man1.pdf | Bin 16975 -> 0 bytes Master/texmf/doc/man/man1/font2afm.1 | 196 - Master/texmf/doc/man/man1/font2afm.man1.pdf | Bin 5311 -> 0 bytes Master/texmf/doc/man/man1/ot2kpx.1 | 186 +- Master/texmf/doc/man/man1/ot2kpx.man1.pdf | Bin 6021 -> 7539 bytes Master/texmf/doc/man/man1/pfm2kpx.1 | 208 - Master/texmf/doc/man/man1/pfm2kpx.man1.pdf | Bin 6179 -> 0 bytes Master/texmf/doc/man/man1/showglyphs.1 | 185 - Master/texmf/doc/man/man1/showglyphs.man1.pdf | Bin 4582 -> 0 bytes Master/tlpkg/libexec/ctan2tds | 17 +- Master/tlpkg/tlpsrc/fontools.tlpsrc | 8 - 120 files changed, 5054 insertions(+), 17435 deletions(-) delete mode 100755 Build/source/texk/texlive/linked_scripts/fontools/cmap2enc delete mode 100755 Build/source/texk/texlive/linked_scripts/fontools/font2afm delete mode 100755 Build/source/texk/texlive/linked_scripts/fontools/pfm2kpx delete mode 100755 Build/source/texk/texlive/linked_scripts/fontools/showglyphs delete mode 120000 Master/bin/alpha-linux/cmap2enc delete mode 120000 Master/bin/alpha-linux/font2afm delete mode 120000 Master/bin/alpha-linux/pfm2kpx delete mode 120000 Master/bin/alpha-linux/showglyphs delete mode 120000 Master/bin/amd64-freebsd/cmap2enc delete mode 120000 Master/bin/amd64-freebsd/font2afm delete mode 120000 Master/bin/amd64-freebsd/pfm2kpx delete mode 120000 Master/bin/amd64-freebsd/showglyphs delete mode 120000 Master/bin/amd64-kfreebsd/cmap2enc delete mode 120000 Master/bin/amd64-kfreebsd/font2afm delete mode 120000 Master/bin/amd64-kfreebsd/pfm2kpx delete mode 120000 Master/bin/amd64-kfreebsd/showglyphs delete mode 120000 Master/bin/i386-cygwin/cmap2enc delete mode 120000 Master/bin/i386-cygwin/font2afm delete mode 120000 Master/bin/i386-cygwin/pfm2kpx delete mode 120000 Master/bin/i386-cygwin/showglyphs delete mode 120000 Master/bin/i386-freebsd/cmap2enc delete mode 120000 Master/bin/i386-freebsd/font2afm delete mode 120000 Master/bin/i386-freebsd/pfm2kpx delete mode 120000 Master/bin/i386-freebsd/showglyphs delete mode 120000 Master/bin/i386-kfreebsd/cmap2enc delete mode 120000 Master/bin/i386-kfreebsd/font2afm delete mode 120000 Master/bin/i386-kfreebsd/pfm2kpx delete mode 120000 Master/bin/i386-kfreebsd/showglyphs delete mode 120000 Master/bin/i386-linux/cmap2enc delete mode 120000 Master/bin/i386-linux/font2afm delete mode 120000 Master/bin/i386-linux/pfm2kpx delete mode 120000 Master/bin/i386-linux/showglyphs delete mode 120000 Master/bin/i386-netbsd/cmap2enc delete mode 120000 Master/bin/i386-netbsd/font2afm delete mode 120000 Master/bin/i386-netbsd/pfm2kpx delete mode 120000 Master/bin/i386-netbsd/showglyphs delete mode 120000 Master/bin/i386-solaris/cmap2enc delete mode 120000 Master/bin/i386-solaris/font2afm delete mode 120000 Master/bin/i386-solaris/pfm2kpx delete mode 120000 Master/bin/i386-solaris/showglyphs delete mode 120000 Master/bin/mips-irix/cmap2enc delete mode 120000 Master/bin/mips-irix/font2afm delete mode 120000 Master/bin/mips-irix/pfm2kpx delete mode 120000 Master/bin/mips-irix/showglyphs delete mode 120000 Master/bin/powerpc-aix/cmap2enc delete mode 120000 Master/bin/powerpc-aix/font2afm delete mode 120000 Master/bin/powerpc-aix/pfm2kpx delete mode 120000 Master/bin/powerpc-aix/showglyphs delete mode 120000 Master/bin/powerpc-linux/cmap2enc delete mode 120000 Master/bin/powerpc-linux/font2afm delete mode 120000 Master/bin/powerpc-linux/pfm2kpx delete mode 120000 Master/bin/powerpc-linux/showglyphs delete mode 120000 Master/bin/sparc-linux/cmap2enc delete mode 120000 Master/bin/sparc-linux/font2afm delete mode 120000 Master/bin/sparc-linux/pfm2kpx delete mode 120000 Master/bin/sparc-linux/showglyphs delete mode 120000 Master/bin/sparc-solaris/cmap2enc delete mode 120000 Master/bin/sparc-solaris/font2afm delete mode 120000 Master/bin/sparc-solaris/pfm2kpx delete mode 120000 Master/bin/sparc-solaris/showglyphs delete mode 120000 Master/bin/universal-darwin/cmap2enc delete mode 120000 Master/bin/universal-darwin/font2afm delete mode 120000 Master/bin/universal-darwin/pfm2kpx delete mode 120000 Master/bin/universal-darwin/showglyphs delete mode 100755 Master/bin/win32/cmap2enc.exe delete mode 100755 Master/bin/win32/font2afm.exe delete mode 100755 Master/bin/win32/pfm2kpx.exe delete mode 100755 Master/bin/win32/showglyphs.exe delete mode 120000 Master/bin/x86_64-darwin/cmap2enc delete mode 120000 Master/bin/x86_64-darwin/font2afm delete mode 120000 Master/bin/x86_64-darwin/pfm2kpx delete mode 120000 Master/bin/x86_64-darwin/showglyphs delete mode 120000 Master/bin/x86_64-linux/cmap2enc delete mode 120000 Master/bin/x86_64-linux/font2afm delete mode 120000 Master/bin/x86_64-linux/pfm2kpx delete mode 120000 Master/bin/x86_64-linux/showglyphs delete mode 120000 Master/bin/x86_64-solaris/cmap2enc delete mode 120000 Master/bin/x86_64-solaris/font2afm delete mode 120000 Master/bin/x86_64-solaris/pfm2kpx delete mode 120000 Master/bin/x86_64-solaris/showglyphs delete mode 100644 Master/texmf-dist/doc/support/fontools/examples/berling/berling.sty delete mode 100644 Master/texmf-dist/doc/support/fontools/examples/berling/berling.sub delete mode 100644 Master/texmf-dist/doc/support/fontools/examples/berling/makeberling delete mode 100644 Master/texmf-dist/doc/support/fontools/examples/berling/mbr_fnst.tex delete mode 100644 Master/texmf-dist/doc/support/fontools/examples/frutiger/frutiger.sty delete mode 100644 Master/texmf-dist/doc/support/fontools/examples/frutiger/frutiger.sub delete mode 100644 Master/texmf-dist/doc/support/fontools/examples/frutiger/lfr_fnst.tex delete mode 100644 Master/texmf-dist/doc/support/fontools/examples/frutiger/makefrutiger delete mode 100644 Master/texmf-dist/doc/support/fontools/examples/palatinox/Palatino_fnst.tex delete mode 100644 Master/texmf-dist/doc/support/fontools/examples/palatinox/make_Palatino delete mode 100644 Master/texmf-dist/doc/support/fontools/examples/palatinox/pala.sub delete mode 100644 Master/texmf-dist/doc/support/fontools/examples/palatinox/palatinox.sty delete mode 100644 Master/texmf-dist/doc/support/fontools/examples/palatinox/unsetSCaps.mtx delete mode 100755 Master/texmf-dist/scripts/fontools/cmap2enc delete mode 100755 Master/texmf-dist/scripts/fontools/font2afm delete mode 100755 Master/texmf-dist/scripts/fontools/pfm2kpx delete mode 100755 Master/texmf-dist/scripts/fontools/showglyphs delete mode 100644 Master/texmf/doc/man/man1/cmap2enc.1 delete mode 100644 Master/texmf/doc/man/man1/cmap2enc.man1.pdf delete mode 100644 Master/texmf/doc/man/man1/font2afm.1 delete mode 100644 Master/texmf/doc/man/man1/font2afm.man1.pdf delete mode 100644 Master/texmf/doc/man/man1/pfm2kpx.1 delete mode 100644 Master/texmf/doc/man/man1/pfm2kpx.man1.pdf delete mode 100644 Master/texmf/doc/man/man1/showglyphs.1 delete mode 100644 Master/texmf/doc/man/man1/showglyphs.man1.pdf diff --git a/Build/source/texk/texlive/linked_scripts/fontools/afm2afm b/Build/source/texk/texlive/linked_scripts/fontools/afm2afm index 80ca105ed90..87d6ef1bbb4 100755 --- a/Build/source/texk/texlive/linked_scripts/fontools/afm2afm +++ b/Build/source/texk/texlive/linked_scripts/fontools/afm2afm @@ -1,115 +1,291 @@ -#!/usr/bin/perl +#! /usr/bin/env perl -use Getopt::Std; -use integer; -use warnings; no warnings qw(uninitialized); +=begin COPYRIGHT -getopts "e:o:", \%options; +---------------------------------------------------------------------------- -$0 =~ s!.*/!!; -die "Usage: $0 -e encoding [-o output] afmfile\n" if - @ARGV != 1 or !$options{e}; + Copyright (C) 2005-2012 Marc Penninga. -if ($options{o} and -e $options{o}) { - die "$0: output file exists\n"; + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation, either version 2 + of the License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to + Free Software Foundation, Inc., + 59 Temple Place, + Suite 330, + Boston, MA 02111-1307, + USA + +---------------------------------------------------------------------------- + +=end COPYRIGHT + +=cut + +use strict; +use warnings; + +use File::Basename; +use Getopt::Long; +use Pod::Usage; + +use v5.10; + +parse_commandline(); + +my $afm = read_afm($ARGV[0]); + +# If user specified encoding, use that; else, use encoding from .afm file +my $enc = $ARGV{encoding} ? read_enc($ARGV{encoding}) + : get_enc($afm) + ; +# Make lookup table to quickly see if a character is present in the encoding +my %char_in_enc = map { ($_ => 1) } @{$enc->{vector}}; + +print_fontinfo($afm->{fontinfo}, $enc->{scheme}); +print_charmetrics($afm->{metrics}, $enc->{vector}); +print_kerndata($afm->{kernpairs}, $afm->{trackkerns}, \%char_in_enc); +print_composites($afm->{composites}, \%char_in_enc); +print "EndFontMetrics\n"; + +close select *STDOUT if $ARGV{output}; + +print_mapentry($afm->{fontinfo}, , $enc->{scheme}) + if $ARGV{encoding} && $ARGV{output}; + +#----------------------------------------------------------------------- +# +#----------------------------------------------------------------------- +sub parse_commandline { + Getopt::Long::GetOptions( + 'help|?' => sub { pod2usage(-verbose => 1) }, + 'encoding=s' => \$ARGV{encoding}, + 'output=s' => \$ARGV{output}, + ) + or pod2usage(-verbose => 0); + + pod2usage(-verbose => 0) if @ARGV != 1; + + if ($ARGV{output}) { + $ARGV{output} .= '.afm' unless $ARGV{output} =~ m/[.]afm\z/xms; + open my $output, '>', $ARGV{output} + or die "[ERROR] can't open '$ARGV{output}': $!"; + select $output; + } + + return; } -if ((chop($fn = `kpsewhich $ARGV[0] 2>&1`) and -e $fn) or - (chop($fn = `findtexmf $ARGV[0] 2>&1`) and -e $fn)) -{ - open AFM, "<$fn" or die "Error: can't open `$fn' - $!\n"; -} -else { - open AFM, "<$ARGV[0]" or - die "Error: can't open `$ARGV[0]' - $!\n"; +#----------------------------------------------------------------------- +# +#----------------------------------------------------------------------- +sub read_afm { + my $filename = shift; + open my $afmfile, '<', $filename + or die "[ERROR] can't open '$filename': $!"; + + my %afm = ( + fontinfo => [], + metrics => [], + kernpairs => [], + trackkerns => [], + composites => [], + ); + + until ((my $line = <$afmfile>) =~ m/StartCharMetrics/xms) { + push @{$afm{fontinfo}}, $line; + } + + for (<$afmfile>) { + when (m/\A\s* C \s/xms) { push @{$afm{metrics}}, $_ } + when (m/\A\s* KPX \s/xms) { push @{$afm{kernpairs}}, $_ } + when (m/\A\s* TrackKern \s/xms) { push @{$afm{trackkerns}}, $_ } + when (m/\A\s* CC \s/xms) { push @{$afm{composites}}, $_ } + } + + close $afmfile; + + return \%afm; } -{ - local $/; - $_ = ; + +#----------------------------------------------------------------------- +# Get encoding name and vector from the specified .enc file +#----------------------------------------------------------------------- +sub read_enc { + my $filename = shift; + + open my $encfile, '<', $filename + or die "[ERROR] can't open '$filename': $!"; + my $data = join ' ', map { s/%.+|\n//xmsg; $_ } <$encfile>; + close $encfile; + + my ($scheme, $encoding) + = $data =~ m{ /([-\w]+) \s* [[] (.+) []] \s* def }xms + or die "[ERROR] parsing encoding file '$filename' failed"; + + return { scheme => $scheme, + vector => [ $encoding =~ m{ /([.\w]+) }xmsg ], + }; } -$Time = localtime; -$FontInfo = /(.*)StartCharMetrics/s ? $1 : ""; -$FontInfo =~ s/(?<=Comment ).*?$/Reencoded at $Time by $0 from $ARGV[0]/m; -$FontInfo =~ s/(?<=ItalicAngle )([\d.]+)/{$1 >= 32768 ? $1 - 65536 : $1}/me; -$FontInfo =~ s/\r+\n/\n/g; -if ($FontInfo =~ /FontName\s+([\w-]+)/) {$FontName = $1} -else {warn "Warning: no FontName found in file `$ARGV[0]'\n"} - -for (/(WX.*?$)/gm) {/N\s+([\w.]+)/ and $WX{$1} = $_} -for (/(KPX.*?$)/gm) {/\s+([\w.]+)\s+([\w.]+)\s+(-?\d+)/ and $KPX{$1}{$2} = $3} - -if ((chop($fn = `kpsewhich $options{e} 2>&1`) and -e $fn) or - (chop($fn = `findtexmf $options{e} 2>&1`) and -e $fn)) -{ - open ENC, "<$fn" or die "Error: can't open `$fn' - $!\n"; -} -else { - open ENC, "<$options{e}" or - die "Error: can't open `$options{e}' - $!\n"; +#----------------------------------------------------------------------- +# Get encoding from the input .afm file +#----------------------------------------------------------------------- +sub get_enc { + my $afm = shift; + + my %enc = ( scheme => 'FontSpecific', vector => [ ('/.undef') x 256 ] ); + + for my $line (@{$afm->{fontinfo}}) { + if ($line =~ m/EncodingScheme \s+ ([-\w]+)/xms) { + $enc{scheme} = $1; + last; + } + } + for my $line (@{$afm->{metrics}}) { + my ($pos, $name) + = $line =~ m/C \s+ ([-]?\d+) .+? N \s+ ([.\w]+)/xms + or die; + $enc{vector}[$pos] = $name unless $pos == -1; + } + + return \%enc; } -chop(@lines = ); -map s!%.*!!, @lines; -$_ = join "", @lines; -($n, $_) = m!/([\w-]+) \s* \[(.*)\] \s+ def!x; -@vector = m!([\w.]+)!g; - -for $i (0 .. $#vector) { - next if $vector[$i] eq ".notdef"; - if ($WX{$vector[$i]} =~ /WX\s+(-?\d+).*?N\s+([\w.]+).*?B\s+(.*?)\s+;/) { - ($WX, $N, $B) = ($1, $2, $3); - push @WX, "C $i ; WX $WX ; N $N ; B $B ;\n"; + +#----------------------------------------------------------------------- +# +#----------------------------------------------------------------------- +sub print_fontinfo { + my ($fontinfo, $scheme) = @_; + + for my $line (@$fontinfo) { + $line = "EncodingScheme $scheme\n" + if $line =~ m/EncodingScheme/xms; + print $line; } - for $j (0 .. $#vector) { - next if $vector[$j] eq ".notdef"; - next unless $KPX{$vector[$i]}{$vector[$j]}; - push @KPX, - "KPX $vector[$i] $vector[$j] $KPX{$vector[$i]}{$vector[$j]}\n"; + + return; +} + +#----------------------------------------------------------------------- +# Print character metrics for characters in specified encoding +#----------------------------------------------------------------------- +sub print_charmetrics { + my ($metrics, $vector) = @_; + + my %metrics = map { m/(WX .+? N \s+ ([.\w]+) .+)/xms; ($2 => $1) } + @$metrics; + + print "StartCharMetrics @{[ scalar grep { $metrics{$_} } @$vector ]}\n"; + for my $i (0 .. 255) { + next unless $metrics{$vector->[$i]}; + print "C $i ; $metrics{$vector->[$i]}"; } + print "EndCharMetrics\n"; + + return; } -if ($options{o}) { - ($e = $options{e}) =~ s!.*/!!; - ($f = $ARGV[0]) =~ s!.*/|\.afm!!g; - ($o = $options{o}) =~ s!.*/|\.afm!!g; - - $x = "pfb"; - for (qw(pfb pfa ttf otf)) { - if (-e "$f.$_" or - (chop($fn = `kpsewhich "$f.$_" 2>&1`) and -e $fn) or - (chop($fn = `findtexmf "$f.$_" 2>&1`) and -e $fn)) - { - $x = $_; - last; - } +#----------------------------------------------------------------------- +# Print kerning data for characters in specified encoding +#----------------------------------------------------------------------- +sub print_kerndata { + my ($kernpairs, $trackkerns, $char_in_enc) = @_; + + my @kernpairs = grep { m/\A\s* KPX \s+ ([.\w]+) \s+ ([.\w]+)/xms + and $char_in_enc->{$1} + and $char_in_enc->{$2} + } + @$kernpairs; + + if (@kernpairs || @$trackkerns) { + print "StartKernData\n"; + if (@kernpairs) { + print "StartKernPairs @{[ scalar @kernpairs ]}\n"; + print @kernpairs; + print "EndKernPairs\n"; + } + if (@$trackkerns) { + print "StartTrackKern @{[ scalar @$trackkerns ]}\n"; + print @$trackkerns; + print "EndTrackKern\n"; + } + print "EndKernData\n"; } - print qq($o $FontName <$f.$x <[$e "$n ReEncodeFont"\n); - - if (open OUT, ">$options{o}") { - select OUT; + + return; +} + +#----------------------------------------------------------------------- +# Print "composite" info for characters in specified encoding +#----------------------------------------------------------------------- +sub print_composites { + my ($composites, $char_in_enc) = @_; + + # Each line mentions several characters: the composite and two or more + # 'base' characters. We only print the line if all characters are + # present in the specified encoding + my @composites; + COMPOSITE: + for my $composite (@$composites) { + my @chars = $composite =~ m/(?:CC \s+ ([.\w]+))/xmsg; + for my $char (@chars) { + next COMPOSITE unless $char_in_enc->{$char}; + } + push @composites, $composite; } - else { - warn "Warning: can't create `$options{o}' - $!\n", - " printing to instead\n"; + + if (@composites) { + print "StartComposites @{[ scalar @composites ]}\n"; + print @composites; + print "EndComposites\n"; } + + return; } -$WX = @WX; -$KPX = @KPX; -print < file =head1 SYNOPSIS -afm2afm B<-e> I [B<-o> I] I +=over 8 + +=item B + +[B<-help>] +[B<-encoding> I] +[B<-output> I] +B + +=back + =head1 DESCRIPTION -This program reencodes an F file. It's mainly intended to be used with -F files that were extracted from TrueType or OpenType fonts, since these -are often too big to be handled with tools like F (Adobe's -CaflischScriptPro-Regular font, for example, contains 1289 glyphs and -278678 kerning pairs, leading to an F file of nearly 9MB). +B re-encodes an F file. + +Metrics (including kerning data) for characters not present in the +chosen encoding are excluded from the output, which resuls in +much smaller files. -Glyphs that are absent from the chosen encoding aren't written to the output, -which yields much smaller output files. +Note that if you don't specify an encoding file, the F file +isn't re-encoded, but the unused data is still pruned. -The program also generates an entry for a F-style map file. +The program also generates an entry for a F-style map file, +but only if the F file has been re-encoded and +the output was written to file +(i.e., if both the I<-encoding> and I<-output> options were specified). -=head1 OPTIONS -Option names were chosen to match those of F. +=head1 OPTIONS AND ARGUMENTS =over 4 -=item B<-e> I +=item B<-help> -Reencode using the encoding given in file I. +Print a short description of the syntax -=item B<-o> I +=item B<-encoding> I -Write the reencoded F to file I instead of C. -The mapfile entry will still be written to C. +Re-encode to the enconding in I -=back +=item B<-output> I + +Write the result to I instead of C. -=head1 FILES +=item B -All input files are searched using B or B when these -commands are available; otherwise only the current working directory -is searched. +The F file to be re-encoded. -=head1 SEE ALSO +=back + +Option names may be shortened to a unique prefix. -F, F, F, F, F. =head1 AUTHOR -Marc Penninga +Marc Penninga + + +=head1 COPYRIGHT + +Copyright (C) 2005-2012 Marc Penninga. + + +=head1 LICENSE + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published +by the Free Software Foundation, either version 2 of the License, +or (at your option) any later version. +A copy of the GNU General Public License is included with B; +see the file F. + + +=head1 DISCLAIMER + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +See the GNU General Public License for more details. + + +=head1 RECENT CHANGES + +(See the source code for the rest of the story.) + +=over 12 + +=item I<2012-02-01> + +Refactored the code; added the "no re-encoding, only pruning" +functionality. + +=back + -=head1 HISTORY +=begin Really_old_history =over 12 @@ -190,8 +416,8 @@ Input files searched using B or B (if available) =item I<2005-04-15> -Updated creation of mapfile entry; look for font file to deduce the correct -font file format (pfb, pfa, ttf). If no font file is found, +Updated creation of mapfile entry; look for font file to deduce the correct +font file format (pfb, pfa, ttf). If no font file is found, pfb is assumed. =item I<2005-04-20> diff --git a/Build/source/texk/texlive/linked_scripts/fontools/autoinst b/Build/source/texk/texlive/linked_scripts/fontools/autoinst index d9b0665ebf1..52fe14b65b4 100755 --- a/Build/source/texk/texlive/linked_scripts/fontools/autoinst +++ b/Build/source/texk/texlive/linked_scripts/fontools/autoinst @@ -4,13 +4,12 @@ ---------------------------------------------------------------------------- - Copyright (C) 2005, 2006, 2007, 2009, 2010, 2011 Marc Penninga. + Copyright (C) 2005-2012 Marc Penninga. - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License - as published by the Free Software Foundation, - either version 2 of the License, or (at your option) - any later version. + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + as published by the Free Software Foundation, either version 2 + of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -18,11 +17,11 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to - Free Software Foundation, Inc., - 59 Temple Place, - Suite 330, - Boston, MA 02111-1307, + along with this program; if not, write to + Free Software Foundation, Inc., + 59 Temple Place, + Suite 330, + Boston, MA 02111-1307, USA ---------------------------------------------------------------------------- @@ -34,114 +33,107 @@ use strict; use warnings; -use Getopt::Long; +use File::Path (); +use File::Spec (); +use Getopt::Long (); +my ($d, $m, $y) = (localtime time)[3 .. 5]; +my $TODAY = sprintf "%04d/%02d/%02d", $y + 1900, $m + 1, $d; -my $USAGE =<<'END_USAGE'; - -'autoinst' is a wrapper around Eddie Kohler's TypeTools -(http://www.lcdf.org/type/), for installing OpenType fonts in LaTeX. - -Usage: autoinst [options] font[s] - -Possible options: - --encoding=ENC[,ENC] Use ENC as text encoding(s) (default: LY1) - - --(no)ts1 Toggle creation of TS1 fonts - --(no)smallcaps Toggle creation of smallcaps shape - --(no)swash Toggle creation of swash shape - --(no)titling Toggle creation of titling shape - --(no)superiors Toggle creation of fonts with superior characters - --(no)inferiors Toggle creation of fonts with inferior characters - --(no)ornaments Toggle creation of ornament fonts - --(no)fractions Toggle creation of fonts with digits for fractions - - --sanserif Install font as sanserif font - --typewriter Install font as typewriter font - --manual Manual mode (see documentation) - --extra="TEXT" Add TEXT to the command line for 'otftotfm' - - --help Print this text - --verbose Make some noise - - font[s] The fonts (either .otf or .ttf) to install. - -Please report any bugs or suggestions to . -END_USAGE +=begin Comment + The next three tables map the names of weights, widths and shapes + to NFSS codes. New entries can be added, but the names should be + all lowercase. Also make sure that the NFSS 'series' attribute + (the concatenation of weight and width) is unique! -=begin Comment + The 'book' and 'regular' weights and the 'regular' width are mapped + to an empty string rather than 'm', because the 'm' disappears when + weight and width are combined into the NFSS series (unless *both* are + 'regular', but we deal with that case separately). - The next three tables map the names of weights, widths and shapes - to NFSS codes. New entries can be added without problems, - as long as the name is in all lowercase. - The 'book' and 'regular' weights and the 'regular' width are mapped - to an empty string rather than 'm', because the 'm' disappears when - weight and width are combined into the NFSS series (unless both are - 'regular', but we deal with that case later on). The 'oblique' (aka 'slanted') shape is mapped to 'it' to make things - easier for ourselves. This means the program will fail for font - families that have both italic and oblique shapes, but I doubt + easier for ourselves. This means the program will fail for + font families that have both italic and oblique shapes, but I doubt whether these exist (apart from Computer Modern, of course). - + =end Comment =cut my %FD_WEIGHT = ( - thin => 't', - ultralight => 'ul', - extralight => 'el', - light => 'l', - book => '', - regular => '', - medium => 'mb', - demibold => 'db', - semibold => 'sb', - bold => 'b', - extrabold => 'eb', - black => 'a', # Not 'k': that means 'book' in fontname - extrablack => 'ea', - heavy => 'h', - ultra => 'ub', - ultrabold => 'ub', - ultrablack => 'ua', + thin => 't', + ultralight => 'ul', + extralight => 'el', + light => 'l', + book => '', + regular => '', + medium => 'mb', + demibold => 'db', + demi => 'db', + semibold => 'sb', + bold => 'b', + extrabold => 'eb', + ultra => 'ub', + ultrabold => 'ub', + black => 'k', + extrablack => 'ek', + ultrablack => 'uk', + heavy => 'h', + poster => 'r', ); my %FD_WIDTH = ( - ultracondensed => 'uc', - extracondensed => 'ec', - condensed => 'c', - cond => 'c', - semicondensed => 'sc', - regular => '', - semiextended => 'sx', - extended => 'x', + ultracompressed => 'up', + extracompressed => 'ep', + compressed => 'p', + comp => 'p', + cmp => 'p', + compact => 'p', + ultracondensed => 'uc', + extracondensed => 'ec', + condensed => 'c', + cond => 'c', + narrow => 'n', + semicondensed => 'sc', + regular => '', + semiextended => 'sx', + extended => 'x', + expanded => 'e', + wide => 'w', ); my %FD_SHAPE = ( - roman => 'n', - italic => 'it', - it => 'it', # Fix for (at least) some Linotype fonts - oblique => 'it', - slanted => 'it', - romani => 'n', - romanii => 'it', # Map one of Silentium Pro's two roman shapes to 'it' + roman => 'n', + upright => 'n', + italic => 'it', + ita => 'it', + it => 'it', + cursive => 'it', + kursiv => 'it', + inclined => 'it', + incline => 'it', + oblique => 'it', + slanted => 'it', + slant => 'it', + romani => 'n', # Adobe Silentium Pro has two roman shapes; + romanii => 'it', # we map the second one to 'it' ); + =begin Comment - The following tables are used for deciding which font families and shapes + The following tables are used in deciding which font families and shapes to generate. Each hash governs one of these aspects: - 'figure style' (lining, oldstyle, tabular, proportional, superior, inferior etc.); each of these will become a separate font family. - - 'variant' shape (normal, small caps, swash, titling or textcomp). - + - 'shape' (normal, small caps, swash, titling or textcomp). - Each key in the %FIGURE_STYLE hash names a figure style; the corresponding + + Each key in the %STYLE hash names a figure style; the corresponding value is an anonymous hash with four key/value pairs: - reqd A list of required OpenType features; - this style is built if the font supports at least one + reqd A list of required OpenType features; + this style is built if the font supports at least *one* of these features. nice A list of optional OpenType features; these are used if the font supports them, but don't @@ -149,35 +141,35 @@ my %FD_SHAPE = ( extra Extra options passed to otftotfm when creating this style. shape An anonymous array of 'variant' shapes to build with this figure style. - - Ornaments are treated as a separate 'figure style'. - This may seem a bit funny, but is actually the easiest way to do it. - - - Each key in the %SHAPE hash names a 'variant' shape; the corresponding - value is (again) an anonymous hash with several key/value pairs: + + Ornaments are treated as a separate 'figure style'. + This may seem a bit weird, but is actually the easiest way to do it. + + + Each key in the %SHAPE hash names a shape; the corresponding value + is (again) an anonymous hash with several key/value pairs: code An anonymous hash with two possible keys: 'n' -> the NFSS code to use for this variant shape - if the basic shape is upright; + if the 'basic shape' is upright; 'it' -> the NFSS code to use for this variant shape - if the basic shape is italic, slanted or oblique; - If the 'n' ('it') entry is missing, the upright (italic) + if the 'basic shape' is italic, slanted or oblique; + If the 'n' or 'it' entry is missing, the upright or italic version of this variant shape will not be built. - reqd A list of required OpenType features; - this shape is built if the font supports at least one + reqd A list of required OpenType features; + this shape is built if the font supports at least *one* of these features. nice A list of optional OpenType features; these are used if the font supports them, but don't prevent this shape from being built when missing. extra Extra options passed to otftotfm when creating this shape. - name A string added to the name of the generated font, + name A string added to the name of the generated font, to make it unique. - + =end Comment =cut -my %FIGURE_STYLE = ( +my %STYLE = ( TLF => { reqd => [], nice => ['lnum', 'tnum'], @@ -273,329 +265,329 @@ my %SHAPE = ( ); -# The official names -my %CODING_SCHEME = ( - fontools_ly1 => 'TEX TYPEWRITER AND WINDOWS ANSI', - fontools_t1 => 'EXTENDED TEX FONT ENCODING - LATIN', - fontools_ot1 => 'TEX TEXT', - fontools_ts1 => 'TEX TEXT COMPANION SYMBOLS 1---TS1', -); +############################################################################ -# Default values for the command line arguments -%ARGV = ( - encoding => 'LY1', - textcomp => '2', # 0 = no, 1 = yes, 2 = (enc eq 'T1' ? yes : no) - manual => '0', # 0 = no, 1 = yes - verbose => '0', # 0 = no, 1 = yes - extra => '', - nfss => 'rm', - smallcaps => '1', # 0 = no, 1 = yes - swash => '1', # 0 = no, 1 = yes - titling => '0', # 0 = no, 1 = yes - superiors => '1', # 0 = no, 1 = yes - inferiors => '0', # 0 = no, 1 = yes - ornaments => '1', # 0 = no, 1 = yes - fractions => '0', # 0 = no, 1 = yes -); -my @time = localtime; -my $date = sprintf "%04d/%02d/%02d", $time[5] + 1900, $time[4] + 1, $time[3]; +#----------------------------------------------------------------------- +# The main routine. What else? +#----------------------------------------------------------------------- +sub main { + ARGV::parse_options(); + + my @fonts = map { Fontinfo::parse_fontinfo($_) } @ARGV; + Fontinfo::assert_unique(@fonts); + + # For each font, figure out the shapes, styles and encodings to generate + my @worklist + = cleanup(expand_encodings(expand_shapes(expand_styles(@fonts)))); + + # Organize the worklist by family, encoding, style, series and shape + my %fddata; + for my $item (@worklist) { + my $family = $item->{font}{family}; + my $encoding = $item->{encoding}[1]; + my $style = $item->{style}; + my $series = $item->{font}{fdseries}; + my $shape = $item->{fdshape}; + my $minsize = $item->{font}{minsize}; + my $maxsize = $item->{font}{maxsize}; + + push @{$fddata{$family}{$encoding}{$style}{$series}{$shape}}, + [ $minsize, $maxsize, $item->{fontname} ]; + } + while (my ($fam, $famdata) = each %fddata) { + LaTeX::write_stylefile($fam, $famdata); + while (my ($enc, $encdata) = each %$famdata) { + while (my ($sty, $stydata) = each %$encdata) { + LaTeX::write_fdfile($fam, $enc, $sty, $stydata); + } + } + } -# ----------------------- subroutine definitions ----------------------- + make_commands(@worklist); + return; +} -sub main { - parse_options(); - - my (%already_seen, %commands, @fd_data, $err_msg); - - FONTFILE: - for my $filename (@ARGV) { - my %fontinfo = read_font_info($filename); - my $unique - = join ',', @fontinfo{qw(family width weight shape min max)}; - if ( $already_seen{$unique} - and $already_seen{$unique} ne $filename) { - $err_msg .= <<"END_PARSE_ERROR"; - -ERROR: I've parsed both '$already_seen{$unique}' - and '$filename' as - - Family $fontinfo{family} - Width $fontinfo{width} - Weight $fontinfo{weight} - Shape $fontinfo{shape} - Size $fontinfo{min}-$fontinfo{max} -END_PARSE_ERROR - } - else { - $already_seen{$unique} = $filename; - } +#----------------------------------------------------------------------- +# Determine which figure styles to create for each font; +# return a list of (font, style) tuples +#----------------------------------------------------------------------- +sub expand_styles { + return map { my $font = $_; + map { { font => $font, style => $_ } } + grep { has_reqd($font, $STYLE{$_}) } + keys %STYLE + } + @_; +} - FIGURE_STYLE: - for my $figure_style (keys %FIGURE_STYLE) { - - # Does the font support this figure style? - if ( @{$FIGURE_STYLE{$figure_style}{reqd}} - and not grep { exists $fontinfo{features}{$_} } - @{$FIGURE_STYLE{$figure_style}{reqd}} ) { - next FIGURE_STYLE; - } - - # If so, create all corresponding shapes - my $basic = $FD_SHAPE{$fontinfo{shape}}; - - SHAPE: - for my $shape (@{$FIGURE_STYLE{$figure_style}{shapes}}) { - next SHAPE if not exists $SHAPE{$shape}; - next SHAPE if not exists $SHAPE{$shape}{code}{$basic}; - - # Does the font support this shape? - if ( @{$SHAPE{$shape}{reqd}} - and not grep { exists $fontinfo{features}{$_} } - @{$SHAPE{$shape}{reqd}}) { - next SHAPE; - } - - # Decide which features to use - my @features = grep { exists $fontinfo{features}{$_} } - ( - @{$FIGURE_STYLE{$figure_style}{reqd}}, - @{$FIGURE_STYLE{$figure_style}{nice}}, - @{$SHAPE{$shape}{reqd}}, - @{$SHAPE{$shape}{nice}}, - ); - - # Remove duplicate features - my %tmp_features; - for my $f (@features) { - $tmp_features{$f} = 1; - } - if ($tmp_features{onum} && $tmp_features{lnum}) { - delete $tmp_features{lnum}; - } - @features = keys %tmp_features; - - # Figure out the name and NFSS code for the encodings - my @encodings; - if ($shape eq 'textcomp') { - @encodings = (['fontools_ts1', 'ts1']); - } - elsif ($figure_style eq 'Orn') { - @encodings = ([make_ornament_encoding(%fontinfo), 'u']); - } - else { - @encodings = map { [lc $_, lc $_] } @{$ARGV{encoding}}; - } +#----------------------------------------------------------------------- +# Determine which shapes to create for each (font, style) combination; +# return a list of (font, style, shape) tuples +#----------------------------------------------------------------------- +sub expand_shapes { + return map { my ($font, $style) = @{$_}{qw(font style)}; + map { { font => $font, style => $style, shape => $_ } } + grep { has_reqd($font, $SHAPE{$_}) } + @{$STYLE{$style}{shapes}}; + } + @_; +} - ENCODING: - for my $enc_ref (@encodings) { - my ($enc_name, $enc_code) = @{$enc_ref}; - $enc_name =~ s/\A (ly1|ot1|t1) \z/fontools_$1/xms; - - # Create unique name for this font - my $fontname = join '-', - $fontinfo{name}, - lc $figure_style, - $SHAPE{$shape}{name}, - $enc_code, - ; - $fontname =~ s/[-]{2,}/-/xmsg; - - # Create the command line for otftotfm - my $command - = join ' ', - 'otftotfm', - "--encoding=$enc_name", - ($ARGV{manual} ? '--pl' : '--automatic'), - "--map-file=$fontinfo{family}.map --no-updmap", - ($filename =~ m/[.]ttf\z/xms - ? '--no-type1' - : ''), - ($CODING_SCHEME{$enc_name} - ? "--coding-scheme=" - . "\"$CODING_SCHEME{$enc_name}\"" - : ''), - (map { "--feature=$_" } @features), - # if there's no 'liga' feature, - # add ligkern commands for common ligatures - ((grep { $_ eq 'liga' } @features) - ? '' - : '--ligkern="f i =: fi" ' - . '--ligkern="f l =: fl" ' - . '--ligkern="f f =: ff" ' - . '--ligkern="ff i =: ffi" ' - . '--ligkern="ff l =: ffl" '), - $FIGURE_STYLE{$figure_style}{extra}, - $SHAPE{$shape}{extra}, - $ARGV{extra}, - '"' . $filename . '"', - $fontname, - ; - - # Save the command and the necessary data for .fd files - push @{$commands{$fontinfo{family}}}, $command; - push @fd_data, - join '|', - $fontinfo{family}, - uc $enc_code, - $figure_style, - $FD_WEIGHT{$fontinfo{weight}} - . $FD_WIDTH{$fontinfo{width}} - || 'm', - $SHAPE{$shape}{code}{$basic}, - sprintf("%04.1f",$fontinfo{min}), - sprintf("%04.1f",$fontinfo{max}), - $fontname, - ; - - if ($ARGV{verbose}) { - printf " %-42s %4s/%s-%s/%s/%s\n", - $fontname, - uc $enc_code, - $fontinfo{family}, - $figure_style, - $FD_WEIGHT{$fontinfo{weight}} - .$FD_WIDTH{$fontinfo{width}} - || 'm', - $SHAPE{$shape}{code}{$basic}, - ; - } - } - } - } - } +#----------------------------------------------------------------------- +# Check if $font has (at least one of the) features mentioned in the +# 'reqd' subtable of $target +#----------------------------------------------------------------------- +sub has_reqd { + my ($font, $target) = @_; - # If parsing failed, flush STDOUT, print the error messages and die - if (defined $err_msg) { - close STDOUT; - die $err_msg . <<'END_GENERAL_PARSE_ERROR'; - - -I suspect your font family contains some unusual weights or widths. -You might try adding missing widths and weights to the tables -'%FD_WIDTH' and '%FD_WEIGHT' at the beginning of the source code; -otherwise, please send a bug report to . -END_GENERAL_PARSE_ERROR - } - - @fd_data = sort @fd_data; - - for my $fd_line (@fd_data) { - my @fd_line = split /[|]/, $fd_line; - $fd_line[5] += 0; - $fd_line[6] += 0; - $fd_line = \@fd_line; - } - - # Adjust size ranges - $fd_data[0][5] = ''; - for my $i (0 .. $#fd_data - 1) { - if (grep { $fd_data[$i][$_] ne $fd_data[$i + 1][$_] } 0 .. 4) { - $fd_data[$i][6] = $fd_data[$i + 1][5] = ''; - } - else { - $fd_data[$i][6] = $fd_data[$i + 1][5]; - } - } - $fd_data[-1][6] = ''; - - # Generate .fd files - my @fd_prev = ('') x 8; - my $FD; - for my $fd_line_ref (@fd_data) { - my @fd_line = @{$fd_line_ref}; - - my $safe = $fd_line[0]; - $safe =~ s/1/One/xmsg; - $safe =~ s/2/Two/xmsg; - $safe =~ s/3/Three/xmsg; - $safe =~ s/4/Four/xmsg; - $safe =~ s/5/Five/xmsg; - $safe =~ s/6/Six/xmsg; - $safe =~ s/7/Seven/xmsg; - $safe =~ s/8/Eight/xmsg; - $safe =~ s/9/Nine/xmsg; - $safe =~ s/0/Zero/xmsg; - - write_style_file($fd_line[0], $safe, @fd_data) - if $fd_line[0] ne $fd_prev[0]; - - if (grep { $fd_line[$_] ne $fd_prev[$_] } 0 .. 2) { - end_fd_file($FD) if $fd_prev[0]; - $FD = start_fd_file(@fd_line[0 .. 2], $safe); - } - - if (grep { $fd_line[$_] ne $fd_prev[$_] } 0 .. 4) { - # Start new fontshape - if (not grep { $fd_line[$_] ne $fd_prev[$_] } 0 .. 2) { - print {$FD} "}{}\n\n"; + return 0 unless defined $target; + return 1 unless @{$target->{reqd}}; + return grep { $font->{feature}{$_} } @{$target->{reqd}}; +} + +#----------------------------------------------------------------------- +# Determine which encodings to use for each (font, style, shape) combi; +# return a list of (font, style, shape, encoding) tuples +#----------------------------------------------------------------------- +sub expand_encodings { + return + map { my ($font, $style, $shape) = @{$_}{qw(font style shape)}; + my @encodings + = $shape eq 'textcomp' ? (['fontools_ts1', 'ts1']) + : $style eq 'Orn' ? ([Fontinfo::get_orn($font), 'u']) + : map { [lc $_, lc $_] } @{$ARGV{encoding}} + ; + map { { font => $font, + style => $style, + shape => $shape, + encoding => $_, + } + } + @encodings; } - printf {$FD} "\\DeclareFontShape{%s}{%s-%s}{%s}{%s}{\n", - @fd_line[1, 0, 2, 3, 4]; + @_; +} + +#----------------------------------------------------------------------- +# Add some finishing touches to the work list +#----------------------------------------------------------------------- +sub cleanup { + my @worklist = @_; + + for my $item (@worklist) { + my ($font, $style, $shape, $encoding) + = @{$item}{qw(font style shape encoding)}; + + # generate unique name for this font + $item->{fontname} = join '-', grep { $_ } $font->{name}, + lc $style, + lc $SHAPE{$shape}{name}, + lc $encoding->[1]; + + # look up NFSS code for font's shape + $item->{fdshape} + = $SHAPE{$shape}{code}{$font->{basicshape}}; + + # compile list of OpenType features to use with this font + my %feature = map { ($_ => 1) } + grep { $font->{feature}{$_} } + ( @{$STYLE{$style}{reqd}}, + @{$STYLE{$style}{nice}}, + @{$SHAPE{$shape}{reqd}}, + @{$SHAPE{$shape}{nice}}, + ); + if ($feature{lnum} && $feature{onum}) { + delete $feature{lnum}; } - - # Write fontshape entry - printf {$FD} " %s \\%s\@\@scale %s\n", - sprintf("%5s-%-5s", '<' . $fd_line[5], $fd_line[6] . '>'), - $safe, - $fd_line[7], - ; - - @fd_prev = @fd_line; + $item->{features} = [ sort keys %feature ]; + + # add finishing touches to name and NFSS code of encoding + $item->{encoding}[0] =~ s/\A (ot1|t1|ly1) \z/fontools_$1/xms; + $item->{encoding}[1] = uc $item->{encoding}[1]; } - - end_fd_file($FD) if $fd_prev[0]; - # Print or execute the generated commands + return @worklist; +} + +#----------------------------------------------------------------------- +# Generate all otftotfm commands, and either save or execute them +#----------------------------------------------------------------------- +sub make_commands { + my @worklist = @_; + + my @commands = map { make_cmdline($_) } @worklist; + + # make sure the last command *does* call updmap + $commands[-1] =~ s/--no-updmap//xms; + if ($ARGV{manual}) { - while (my ($fam, $cmds_ref) = each %commands) { - open my $BAT, '>', "$fam.bat" - or die "ERROR: can't create '$fam.bat' - $!"; - print {$BAT} "$_\n" for @{$cmds_ref}; - close $BAT; - } + open my $BAT, '>', 'autoinst.bat' + or die "[ERROR] Can't create 'autoinst.bat': $!"; + print {$BAT} "$_\n" for @commands; + close $BAT; } else { - # Remove the --no-updmap option from the last command for each family - map { $_->[-1] =~ s/--no-updmap//xms } values %commands; - - for my $cmds_ref (values %commands) { - for my $cmd (@{$cmds_ref}) { - print "$cmd\n"; - system $cmd and warn <<'END_OTFTOTFM_WARNING'; - -WARNING: 'otftotfm' finished with a non-zero return code; - I'm afraid something went wrong! - -END_OTFTOTFM_WARNING - } + if (grep { system $_ } @commands) { + warn "[WARNING] 'otftotfm' returned non-zero; something's wrong!"; } } + + return; +} + +# The official names for various coding schemes +my %SCHEME = ( + fontools_ly1 => 'TEX TYPEWRITER AND WINDOWS ANSI', + fontools_t1 => 'EXTENDED TEX FONT ENCODING - LATIN', + fontools_ot1 => 'TEX TEXT', + fontools_ts1 => 'TEX TEXT COMPANION SYMBOLS 1---TS1', +); + +#----------------------------------------------------------------------- +# Generate a command line for otftotfm +#----------------------------------------------------------------------- +sub make_cmdline { + my $item = shift; + + return join ' ', 'otftotfm', + ($ARGV{manual} ? '--pl' : '--automatic'), + "--encoding=$item->{encoding}[0]", + set_targetdirs($item->{font}{family}), + '--no-updmap', + ($item->{font}{filename} =~ m/[.]ttf\z/xms + ? '--no-type1' + : ''), + ($SCHEME{$item->{encoding}[0]} + ? qq(--coding-scheme="$SCHEME{$item->{encoding}[0]}") + : ''), + (map { "--feature=$_" } @{$item->{features}}), + ((grep { $_ eq 'liga' } @{$item->{features}}) + ? '' + : ( '--ligkern="f i =: fi"', + '--ligkern="f l =: fl"', + '--ligkern="f f =: ff"', + '--ligkern="ff i =: ffi"', + '--ligkern="ff l =: ffl"' )), + $STYLE{$item->{style}}{extra}, + $SHAPE{$item->{shape}}{extra}, + $ARGV{extra}, + qq("$item->{font}{filename}"), + $item->{fontname}, + ; +} + +#----------------------------------------------------------------------- +# Return a string with all "directory" options for otftotfm set +#----------------------------------------------------------------------- +sub set_targetdirs { + my $family = shift; + + my %dir = map { ($_ => File::Spec->catdir( + $ARGV{target}, 'fonts', $_, 'lcdftools', $family)) + } + qw(tfm vf pl vpl type1 truetype type42); + + $dir{$_} = File::Spec->catdir( + $ARGV{target}, 'fonts', $_, 'dvips', 'lcdftools') + for qw(enc map); + + File::Path::make_path(values %dir); + + my $result = join ' ', map { "--${_}-directory=$dir{$_}" } + qw(tfm vf pl vpl type1 truetype type42); + $result .= " --encoding-directory=$dir{enc} --map-file=" + . File::Spec->catfile($dir{map}, "${family}.map"); + + return $result; } -# ------------------------------------------------------------------------ +############################################################################ + + +package ARGV; + +my $USAGE =<<'END_USAGE'; + +'autoinst' is a wrapper around Eddie Kohler's TypeTools +(http://www.lcdf.org/type/), for installing OpenType fonts in LaTeX. + +Usage: autoinst [options] font[s] + +Possible options: + -encoding=ENC[,ENC]* Specify text encoding(s) (default: OT1,T1,LY1) + + -(no)ts1 Toggle creation of TS1 fonts + -(no)smallcaps Toggle creation of smallcaps shape + -(no)swash Toggle creation of swash shape + -(no)titling Toggle creation of titling shape + -(no)superiors Toggle creation of fonts with superior characters + -(no)inferiors Toggle creation of fonts with inferior characters + -(no)ornaments Toggle creation of ornament fonts + -(no)fractions Toggle creation of fonts with digits for fractions + + -sanserif Install font as sanserif font + -typewriter Install font as typewriter font + -extra="TEXT" Add TEXT to the command line for 'otftotfm' + -target="DIRECTORY" Install files into specified TEXMF tree + -manual Manual mode (see documentation) + + -(no)figurekern Keep or remove kerns between tabular figures + + -help Print this text + -verbose Make some noise + + font[s] The fonts (either .otf or .ttf) to install. + +Please report any bugs or suggestions to . +END_USAGE + +# Default values for the command-line arguments +%ARGV = ( + encoding => 'OT1,T1,LY1', + textcomp => '2', # 0 = no, 1 = yes, 2 = (enc eq 'T1' ? yes : no) + smallcaps => '1', # 0 = no, 1 = yes + swash => '1', # 0 = no, 1 = yes + titling => '1', # 0 = no, 1 = yes + superiors => '1', # 0 = no, 1 = yes + inferiors => '0', # 0 = no, 1 = yes + ornaments => '1', # 0 = no, 1 = yes + fractions => '0', # 0 = no, 1 = yes + nfss => 'rm', + extra => '', + target => '', + manual => '0', # 0 = no, 1 = yes + verbose => '0', # 0 = no, 1 = yes + figurekern => '1', # 0 = no, 1 = yes +); + +#----------------------------------------------------------------------- +# Process command-line arguments +#----------------------------------------------------------------------- sub parse_options { my $cmdline = "$0 " . join ' ', @ARGV; - - GetOptions( - 'help' => sub { print $USAGE; exit }, - 'encoding=s' => \$ARGV{encoding}, - 'ts1!' => \$ARGV{textcomp}, - 'manual' => \$ARGV{manual}, - 'verbose' => \$ARGV{verbose}, - 'extra=s' => \$ARGV{extra}, - 'sanserif' => sub { $ARGV{nfss} = 'sf' }, - 'typewriter' => sub { $ARGV{nfss} = 'tt' }, - 'smallcaps!' => \$ARGV{smallcaps}, - 'swash!' => \$ARGV{swash}, - 'titling!' => \$ARGV{titling}, - 'superiors!' => \$ARGV{superiors}, - 'inferiors!' => \$ARGV{inferiors}, - 'ornaments!' => \$ARGV{ornaments}, - 'fractions!' => \$ARGV{fractions}, + + Getopt::Long::GetOptions( + 'help|?' => sub { print $USAGE; exit; }, + 'encoding=s' => \$ARGV{encoding}, + 'ts1!' => \$ARGV{textcomp}, + 'smallcaps!' => \$ARGV{smallcaps}, + 'swash!' => \$ARGV{swash}, + 'titling!' => \$ARGV{titling}, + 'superiors!' => \$ARGV{superiors}, + 'inferiors!' => \$ARGV{inferiors}, + 'ornaments!' => \$ARGV{ornaments}, + 'fractions!' => \$ARGV{fractions}, + 'sanserif' => sub { $ARGV{nfss} = 'sf' }, + 'typewriter' => sub { $ARGV{nfss} = 'tt' }, + 'extra=s' => \$ARGV{extra}, + 'target=s' => \$ARGV{target}, + 'manual' => \$ARGV{manual}, + 'figurekern!' => \$ARGV{figurekern}, + 'verbose' => \$ARGV{verbose}, ) or die "$USAGE"; @@ -605,33 +597,57 @@ sub parse_options { if (!$ARGV{swash} ) { delete $SHAPE{swash} } if (!$ARGV{titling} ) { delete $SHAPE{titling} } - if (!$ARGV{superiors}) { delete $FIGURE_STYLE{Sup} } - if (!$ARGV{inferiors}) { delete $FIGURE_STYLE{Inf} } - if (!$ARGV{ornaments}) { delete $FIGURE_STYLE{Orn} } - if (!$ARGV{fractions}) { delete @FIGURE_STYLE{qw(Numr Dnom)} } - + if (!$ARGV{superiors}) { delete $STYLE{Sup} } + if (!$ARGV{inferiors}) { delete $STYLE{Inf} } + if (!$ARGV{ornaments}) { delete $STYLE{Orn} } + if (!$ARGV{fractions}) { delete @STYLE{qw(Numr Dnom)} } + $ARGV{encoding} =~ s/\s+//xmsg; my @textencodings = grep { $_ ne 'TS1' } - map { uc } + map { uc } split /,/, $ARGV{encoding}; $ARGV{encoding} = \@textencodings; # TS1-encoded fonts are generated if: - # - text encoding is T1 and the user didn't turn off TS1, or - # - the user explicitly asked for TS1 - if ( - !( (grep { $_ eq 'T1' } @{$ARGV{encoding}} and $ARGV{textcomp}) - or $ARGV{textcomp} == 1 - )) { + # - the user explicitly asked for TS1, or + # - the text encodings contain T1 and the user didn't turn off TS1 + unless ( (grep { $_ eq 'T1' } @{$ARGV{encoding}} and $ARGV{textcomp}) + or $ARGV{textcomp} == 1) + { delete $SHAPE{textcomp}; } - + + if ($ARGV{manual}) { + warn "[WARNING] option '--target' overridden by '--manual'!" + if $ARGV{target}; + $ARGV{target} = File::Spec->curdir(); + } + elsif (not $ARGV{target}) { + my @dirs = grep { -w $_ } + map { split m/:/xms, substr $_, 0, -1 } + ( `kpsewhich --expand-path='\$TEXMFLOCAL'`, + `kpsewhich --expand-path='\$TEXMFHOME'`, ); + $ARGV{target} = $dirs[0] || File::Spec->curdir(); + } + + if (!$ARGV{figurekern}) { + my @digits = qw(zero one two three four five six seven eight nine); + my $tkern + = join ' ', map { my $left = $_; + map { qq(--ligkern="$left {} $_") } @digits + } + @digits; + + $STYLE{TLF}{extra} = $tkern; + $STYLE{TOsF}{extra} = $tkern; + } + if ($ARGV{verbose}) { print <<"END_ARGUMENTS"; $cmdline - + I'm using the following options: encoding(s): @{[ join ', ', @{$ARGV{encoding}} ]} @@ -639,279 +655,379 @@ I'm using the following options: : $ARGV{nfss} eq 'sf' ? '(sanserif)' : $ARGV{nfss} eq 'tt' ? '(typewriter)' : '(unknown)' - ]} + ]} + + (no)ts1: @{[ $SHAPE{textcomp} ? 'ts1' : 'nots1' ]} + (no)smallcaps: @{[ $ARGV{smallcaps} ? 'smallcaps' : 'nosmallcaps' ]} + (no)swash: @{[ $ARGV{swash} ? 'swash' : 'noswash' ]} + (no)titling: @{[ $ARGV{titling} ? 'titling' : 'notitling' ]} + (no)superiors: @{[ $ARGV{superiors} ? 'superiors' : 'nosuperiors' ]} + (no)inferiors: @{[ $ARGV{inferiors} ? 'inferiors' : 'noinferiors' ]} + (no)ornaments: @{[ $ARGV{ornaments} ? 'ornaments' : 'noornaments' ]} + (no)fractions: @{[ $ARGV{fractions} ? 'fractions' : 'nofractions' ]} - (no)ts1: @{[ $SHAPE{textcomp} ? 'ts1' : 'nots1' ]} - (no)smallcaps: @{[ $ARGV{smallcaps} ? 'smallcaps' : 'nosmallcaps' ]} - (no)swash: @{[ $ARGV{swash} ? 'swash' : 'noswash' ]} - (no)titling: @{[ $ARGV{titling} ? 'titling' : 'notitling' ]} - (no)superiors: @{[ $ARGV{superiors} ? 'superiors' : 'nosuperiors' ]} - (no)inferiors: @{[ $ARGV{inferiors} ? 'inferiors' : 'noinferiors' ]} - (no)ornaments: @{[ $ARGV{ornaments} ? 'ornaments' : 'noornaments' ]} - (no)fractions: @{[ $ARGV{fractions} ? 'fractions' : 'nofractions' ]} + verbosity: @{[ $ARGV{verbose} ? 'verbose' : 'quiet' ]} + target: $ARGV{target} + auto/manual: @{[ $ARGV{manual} ? 'manual' : 'automatic' ]} extra: @{[ $ARGV{extra} || 'empty' ]} - auto/manual: @{[ $ARGV{manual} ? 'manual' : 'automatic' ]} - verbosity: @{[ $ARGV{verbose} ? 'verbose' : 'silent' ]} + figurekern: @{[ $ARGV{figurekern} ? 'keep' : 'discard' ]} END_ARGUMENTS } } -# ------------------------------------------------------------------------ - -sub read_font_info { - my ($fontfile) = @_; - - my %info = (); - - # Read some general info about the font - open my $OTFINFO, '-|', "otfinfo --info \"$fontfile\"" - or die "ERROR: 'otfinfo --info \"$fontfile\"' failed"; - - LINE: - for my $line (<$OTFINFO>) { - my ($key, $val) = $line =~ m/([^:]+) :\s* ([^\n]+)/xms - or next LINE; - $val =~ s/[^-\w]//xmsg; - $info{$key} = $val; - } - close $OTFINFO; - if ($info{Family} =~ m/\A (.+ (?: OT | Pro))/xms) { - $info{Family} = $1; +############################################################################ + + +package Fontinfo; + +#----------------------------------------------------------------------- +# Return ref to hash with all relevant info about this font +#----------------------------------------------------------------------- +sub parse_fontinfo { + my ($filename) = @_; + + my $info = { + filename => $filename, + width => 'regular', + weight => 'regular', + shape => 'roman', + minsize => 0, + maxsize => 0, + }; + + parse_basicinfo($info); + parse_sizeinfo($info); + parse_features($info); + + if ($ARGV{verbose}) { + print <<"END_FONTINFO"; +$info->{filename} + Name: $info->{name} + Family: $info->{family} + Subfamily: $info->{subfamily} + Width: $info->{width} + Weight: $info->{weight} + Shape: $info->{shape} + Size: $info->{minsize}-$info->{maxsize} + Features: @{[ join ', ', sort keys %{$info->{feature}} ]} + +END_FONTINFO } - - $info{'Full name'} =~ s/$info{Family}//xmsg; - $info{'Full name'} = lc $info{'Full name'}; - $info{Family} =~ s/\A (?: Adobe | ITC ) | LT | MT//xmsg; - - # Set default - my %fontinfo = ( - filename => $fontfile, - name => $info{'PostScript name'}, - family => $info{Family}, - width => 'regular', - weight => 'regular', - shape => 'roman', - min => 0, - max => 0, - features => {}, - ); - - # Try to match width, weight and (basic) shape - WIDTH: - for my $width (map { quotemeta } - reverse sort - { length($a) <=> length($b) || $a cmp $b } - keys %FD_WIDTH) - { - if ($info{'Full name'} =~ s/$width//xmsi) { - $fontinfo{width} = $width; - last WIDTH; + + return $info; +} + +# table for converting digits in font names to text (safer for LaTeX) +my @DIGITS = qw(Zero One Two Three Four Five Six Seven Eight Nine); + +#----------------------------------------------------------------------- +# Get some basic info (family, weight, width, shape) about this font +#----------------------------------------------------------------------- +sub parse_basicinfo { + my $info = shift; + + open my $otfinfo, '-|', qq(otfinfo --info "$info->{filename}") + or die "[ERROR] 'otfinfo --info $info->{filename}' failed"; + my %data = map { my ($k,$v) = m/\A\s* ([^:]+?) \s*:\s* ([^\r\n]+)/xms; + $k =~ s/\s+//xmsg; + $v =~ s/\s+//xmsg; + (lc $k => $v); + } + grep { m/\A\s* [^:]+? \s*:\s* [^\r\n]+/xms } <$otfinfo>; + close $otfinfo; + + $data{family} = $data{preferredfamily} || $data{family}; + $data{subfamily} = $data{preferredsubfamily} || $data{subfamily}; + $data{fullname} =~ s/\A$data{family}//xms; + $data{fullname} = lc $data{fullname}; + $data{family} =~ s/\A(?: Adobe | ITC | LT | MT)//xms; + $data{family} =~ s/(\d)/$DIGITS[$1]/xmsge; + + for my $width (mqrs(keys %FD_WIDTH)) { + if ($data{fullname} =~ s/${width}//xmsi) { + $info->{width} = $width; + last; } } - - WEIGHT: - for my $weight (map { quotemeta } - reverse sort - { length($a) <=> length($b) || $a cmp $b } - keys %FD_WEIGHT) - { - if ($info{'Full name'} =~ s/$weight//xmsi) { - $fontinfo{weight} = $weight; - last WEIGHT; + + for my $weight (mqrs(keys %FD_WEIGHT)) { + if ($data{fullname} =~ s/${weight}//xmsi) { + $info->{weight} = $weight; + last; } } - SHAPE: - for my $shape (map { quotemeta } - reverse sort - { length($a) <=> length($b) || $a cmp $b } - keys %FD_SHAPE) - { - if ($info{'Full name'} =~ s/$shape//xmsi) { - $fontinfo{shape} = $shape; - last SHAPE; + + for my $shape (mqrs(keys %FD_SHAPE)) { + if ($data{fullname} =~ s/${shape}//xmsi) { + $info->{shape} = $shape; + last; } } - - # Read optical size info - open $OTFINFO, '-|',"otfinfo --optical-size \"$fontfile\"" - or die "ERROR: 'otfinfo --optical-size \"$fontfile\"' failed"; - if (my ($fm, $to) - = <$OTFINFO> =~ m/ - [(] - ( [\d.]+ ) \s* pt, \s* - ( [\d.]+ ) \s* pt \s* - []] - /xms) { - # Work around some known bugs - if ($fontinfo{name} eq 'GaramondPremrPro-It' - && $fm == 6 - && $to == 8.9) { - @fontinfo{qw(min max)} = (8.9, 14.9); - } - elsif ($fontinfo{family} eq 'KeplerStd' - && $info{Subfamily} =~ m/Caption/xms - && $fm == 8.9 - && $to == 13.9) { - @fontinfo{qw(min max)} = (6, 8.9); - } - elsif ($fontinfo{family} eq 'KeplerStd' - && $info{Subfamily} =~ m/Subhead/xms - && $fm == 8.9 - && $to == 13.9) { - @fontinfo{qw(min max)} = (13.9, 23); - } - elsif ($fontinfo{family} eq 'KeplerStd' - && $info{Subfamily} =~ m/Display/xms - && $fm == 8.9 - && $to == 13.9) { - @fontinfo{qw(min max)} = (23, 72); - } - else { - @fontinfo{qw(min max)} = ($fm, $to); + + $data{subfamily} =~ s/$info->{width}//xmsi; + $data{subfamily} =~ s/$info->{weight}//xmsi; + $data{subfamily} =~ s/$info->{shape}//xmsi; + + $info->{name} = $data{postscriptname}; + $info->{family} = $data{family}; + $info->{subfamily} = $data{subfamily}; + + $info->{basicshape} = $FD_SHAPE{$info->{shape}}; + $info->{fdseries} + = ($FD_WEIGHT{$info->{weight}} . $FD_WIDTH{$info->{width}}) || 'm'; + + return $info; +} + +#----------------------------------------------------------------------- +# When matching against data, try longer strings before shorter ones +#----------------------------------------------------------------------- +sub mqrs { + return map { quotemeta } reverse sort { length($a) <=> length($b) } @_; +} + +#----------------------------------------------------------------------- +# Get all features this font supports +#----------------------------------------------------------------------- +sub parse_features { + my $info = shift; + + open my $otfinfo, '-|', qq(otfinfo --features "$info->{filename}") + or die "[ERROR] 'otfinfo --features $info->{filename}' failed"; + %{$info->{feature}} = map { (substr($_, 0, 4) => 1) } <$otfinfo>; + close $otfinfo; + + open $otfinfo, '-|', qq(otfinfo --tables "$info->{filename}") + or die "[ERROR] 'otfinfo --tables $info->{filename}' failed"; + $info->{feature}{kern} = 1 if grep { m/\d+ \s+ kern/xms } <$otfinfo>; + close $otfinfo; + + return $info; +} + +#----------------------------------------------------------------------- +# Get the optical sizes for this font +#----------------------------------------------------------------------- +sub parse_sizeinfo { + my $info = shift; + + open my $otfinfo, '-|', qq(otfinfo --optical-size "$info->{filename}") + or die "[ERROR] 'otfinfo --optical-size $info->{filename}' failed"; + + if (my ($minsize, $maxsize) = <$otfinfo> =~ m/[(] ([\d.]+) \s* pt, \s* + ([\d.]+) \s* pt \s* []]/xms ) + { + # fix some known bugs + if ($info->{name} eq 'GaramondPremrPro-It' + && $minsize == 6 && $maxsize == 8.9) + { + ($minsize, $maxsize) = (8.9, 14.9); } - } - close $OTFINFO; - - # See what features this font provides - open $OTFINFO, '-|',"otfinfo --features \"$fontfile\"" - or die "ERROR: 'otfinfo --features \"$fontfile\"' failed"; - for my $line (<$OTFINFO>) { - if ($line =~ m/\A (\w{4}) \s+/xms) { - $fontinfo{features}{$1} = 1; + elsif ($info->{family} eq 'KeplerStd' + && $info->{subfamily} =~ m/Caption/xms + && $minsize == 8.9 && $maxsize == 13.9) + { + ($minsize, $maxsize) = (6, 8.9); } - } - close $OTFINFO; - - # Check if there's a "kern" table - open $OTFINFO, '-|',"otfinfo --tables \"$fontfile\"" - or die "ERROR: 'otfinfo --tables \"$fontfile\"' failed"; - for my $line (<$OTFINFO>) { - if ($line =~ m/\d+ \s+ (\w{4}) \s+/xms && $1 eq 'kern') { - $fontinfo{features}{kern} = 1; - last; + elsif ($info->{family} eq 'KeplerStd' + && $info->{subfamily} =~ m/Subhead/xms + && $minsize == 8.9 && $maxsize == 13.9) + { + ($minsize, $maxsize) = (13.9, 23); } - } - close $OTFINFO; - - if ($ARGV{verbose}) { - print <<"END_FONT_INFO"; - -$fontfile: - Family $fontinfo{family} - Width $fontinfo{width} - Weight $fontinfo{weight} - Shape $fontinfo{shape} - Size @{[ $fontinfo{min} || '']}-@{[ $fontinfo{max} || '' ]} -END_FONT_INFO - - my @features = sort keys %{$fontinfo{features}}; - my $prefix = ' Features '; - while (@features) { - print $prefix, join(' ', splice @features, 0, 10), "\n"; - $prefix = ' ' x length $prefix; + elsif ($info->{family} eq 'KeplerStd' + && $info->{subfamily} =~ m/Display/xms + && $minsize == 8.9 && $maxsize == 13.9) + { + ($minsize, $maxsize) = (23, 72); } - print "\n"; + + @{$info}{qw(minsize maxsize)} = ($minsize, $maxsize); } - - return %fontinfo; + close $otfinfo; + + return $info; } -=begin Comment +# Error messages, used in assert_unique() +my $WARN_PARSE =<<'END_WARN_PARSE'; +[WARNING] I failed to parse all fonts in a unique way, so I will split + your font family into multiple subfamilies and try again: - Ornament glyph names vary across fonts, so we generate font-specific - encoding vectors. - This is skipped if a file `_orn.enc' is found in the current - directory, so the user can provide her own vector if she wants to. + %s -=end Comment + Please check the output! -=cut +END_WARN_PARSE -sub make_ornament_encoding { - my (%fontinfo) = @_; +my $ERR_PARSE =<<'END_ERR_PARSE'; +[ERROR] I failed to parse all fonts in a unique way; + presumably some fonts have unusual widths, weights or shapes. - my $fontfile = $fontinfo{filename}; - my $enc_name = $fontinfo{family} . '_orn'; - - if (not -e "$enc_name.enc") { + Try one of the following: + - Run 'autoinst' on a smaller set of fonts, + omitting the ones that weren't parsed correctly; + - Add the missing widths, weights or shapes to the tables + '%FD_WIDTH', '%FD_WEIGHT' or '%FD_SHAPE' near the top + of the source code; + + Please also send a bug report to the author. + +END_ERR_PARSE + +my $ERR_DETAIL =<<'END_ERR_DETAIL'; +[ERROR] I've parsed both %s + and %s as + + Family: %s + Width: %s + Weight: %s + Shape: %s + Size: %s-%s + +END_ERR_DETAIL +#----------------------------------------------------------------------- +# Assert all font infos are unique +#----------------------------------------------------------------------- +sub assert_unique { + my @fonts = @_; + + # These attributes should uniquely identify each font + my @attributes = qw(family width weight shape minsize maxsize); + + ATTEMPT: + for my $attempt (1 .. 2) { + my (%seen, $err_details); + for my $font (@fonts) { + my $key + = join "\x00", + @{$font}{ @attributes }; + + if ($seen{$key}) { + $err_details .= sprintf $ERR_DETAIL, + $seen{$key}{filename}, + $font->{filename}, + @{$font}{ @attributes }; + } + else { + $seen{$key} = $font; + } + } + + # If the font infos aren't unique, append 'Subfamily' to 'Family' + # and try again + if ($err_details) { + if ($attempt == 1) { + $err_details =~ s/\[ERROR\]/[WARNING]/xmsg; + warn $err_details; + + for my $font (@fonts) { + $font->{family} .= $font->{subfamily}; + } + + my @subfamilies + = sort keys %{{ map { ($_->{family} => 1) } @fonts }}; + warn sprintf $WARN_PARSE, join ', ', @subfamilies; + + next ATTEMPT; + } + else { + die $err_details, $ERR_PARSE; + } + } + + last ATTEMPT; + } + + return 1; +} + +#----------------------------------------------------------------------- +# Generate (font-specific) encoding vector for ornament glyphs +#----------------------------------------------------------------------- +sub get_orn { + my ($font) = @_; + + my $fontfile = $font->{filename}; + my $enc_name = $font->{family} . '_orn'; + + if (not -e "$enc_name.enc") { # Default ornament names: 'orn.' plus three digits my @encoding = map { sprintf "orn.%03d", $_ } 1 .. 256; - - open my $OTFINFO, '-|', "otfinfo --glyphs \"$fontfile\"" - or die "ERROR: 'otfinfo --glyphs \"$fontfile\"' failed"; + + open my $OTFINFO, '-|', qq(otfinfo --glyphs "$font->{filename}") + or die "[ERROR] 'otfinfo --glyphs $font->{filename}' failed"; chop(my @glyphnames = <$OTFINFO>); close $OTFINFO; # Test for some known alternative names (probably not exhaustive) - my @ornaments - = sort grep { m/\A (?:orn|u2022[.]|word[.]|hand|bullet[.]) | [.]orn \z/xms } + my @ornaments + = sort grep { m/\A (?: orn|u2022[.]|word[.]|hand|bullet[.]) + | [.]orn \z/xms + } @glyphnames; - - if (@ornaments > 256) { - @encoding = @ornaments[0 .. 255]; - } - else { - @encoding[0 .. $#ornaments] = @ornaments; - } - open my $ORNAMENTS, '>', "$enc_name.enc" - or die "ERROR: can't create '$enc_name.enc' - $!"; - - print {$ORNAMENTS} "/$fontinfo{family}OrnamentEncoding [\n"; - map { print {$ORNAMENTS} " /$_\n" } @encoding; - print {$ORNAMENTS} "] def\n"; - close $ORNAMENTS; + @encoding[0 .. $#ornaments] = @ornaments; + + open my $ORN, '>', "$enc_name.enc" + or die "[ERROR] Can't create '$enc_name.enc': $!"; + + print {$ORN} "/$font->{family}OrnamentEncoding [\n"; + map { print {$ORN} " /$_\n" } @encoding[0 .. 255]; + print {$ORN} "] def\n"; + close $ORN; } - + return $enc_name; } -# ------------------------------------------------------------------------ - -sub write_style_file { - my ($family, $safe, @fd_data) = @_; - - my (%seen_enc, %seen_style, %seen_series, %seen_shape); - - LINE: - for my $line_ref (@fd_data) { - my ($fam, $enc, $style, $series, $shape) = @{$line_ref}[0 .. 4]; - next LINE if $fam ne $family; - $seen_enc{$enc} = 1; - $seen_style{$style} = 1; - $seen_series{$series} = 1; - $seen_shape{$shape} = 1; - } - - open my $STYLE, '>', "$family.sty" - or die "ERROR: can't create '$family.sty' - $!"; - print {$STYLE} <<"END_STY_HEADER"; -%%Generayed by autoinst on $date + +############################################################################ + + +package LaTeX; + +#----------------------------------------------------------------------- +# Create a style file for LaTeX +#----------------------------------------------------------------------- +sub write_stylefile { + my ($fam, $data) = @_; + + my %seen = %{ get_keys($data) }; + + my $fn = sprintf "%s.sty", $fam; + my $dir = File::Spec->catdir($ARGV{target}, 'tex', 'latex', $fam); + File::Path::make_path($dir); + $fn = File::Spec->catfile($dir, $fn); + open my $STY, '>', $fn or die "[ERROR] Can't create '$fn': $!"; + + print {$STY} <<"END_STY_HEADER"; +%% Generated by autoinst on $TODAY %% \\NeedsTeXFormat{LaTeX2e} -\\ProvidesPackage{$family} - [$date (autoinst) Style file for $family.] - +\\ProvidesPackage{$fam} + [$TODAY (autoinst) Style file for $fam.] + END_STY_HEADER - - my $textenc = join ',', grep { $_ ne 'OT1' } @{$ARGV{encoding}}; - - print {$STYLE} "\\RequirePackage[$textenc]{fontenc}\n" if $textenc; - print {$STYLE} "\\RequirePackage{textcomp}\n" if $seen_enc{TS1}; - - print {$STYLE} <<'END_STY_FONTAXES_START'; + + my $enc = join ',', grep { $_ ne 'OT1' } @{$ARGV{encoding}}; + + print {$STY} "\\RequirePackage[$enc]{fontenc}\n" if $enc; + print {$STY} "\\RequirePackage{textcomp}\n" if $seen{TS1}; + + print {$STY} <<'END_STY_FONTAXES_START'; \IfFileExists{fontaxes.sty}{ \RequirePackage{fontaxes} END_STY_FONTAXES_START - if ($seen_shape{tl} || $seen_shape{tlit}) { - print {$STYLE} <<'END_STY_FONTAXES_TL'; + if ($seen{tl} or $seen{tlit}) { + print {$STY} <<'END_STY_FONTAXES_TL'; \providecommand{\tldefault}{tl} \DeclareRobustCommand\tlshape{\not@math@alphabet\tlshape\relax \fontsecondaryshape\tldefault\selectfont} @@ -919,82 +1035,79 @@ END_STY_FONTAXES_START \let\texttitling\texttl \fa@naming@exception{shape}{{n}{tl}}{tl} \fa@naming@exception{shape}{{it}{tl}}{tlit} - + END_STY_FONTAXES_TL } - if ($seen_shape{nw} || $seen_shape{sw}) { - print {$STYLE} <<'END_STY_FONTAXES_SW'; + if ($seen{nw} or $seen{sw}) { + print {$STY} <<'END_STY_FONTAXES_SW'; \DeclareRobustCommand\swshape{\not@math@alphabet\swshape\relax \fontprimaryshape\itdefault\fontsecondaryshape\swdefault\selectfont} \fa@naming@exception{shape}{{n}{sw}}{nw} \fa@naming@exception{shape}{{it}{sw}}{sw} - + END_STY_FONTAXES_SW } - if ($seen_style{Sup}) { - print {$STYLE} <<'END_STY_FONTAXES_SUP'; + if ($seen{Sup}) { + print {$STY} <<'END_STY_FONTAXES_SUP'; \fa@naming@exception{figures}{{superior}{proportional}}{Sup} \fa@naming@exception{figures}{{superior}{tabular}}{Sup} \def\sufigures{\@nomath\sufigures \fontfigurestyle{superior}\selectfont} \DeclareTextFontCommand{\textsu}{\sufigures} \let\textsuperior\textsu - + END_STY_FONTAXES_SUP } - if ($seen_style{Inf}) { - print {$STYLE} <<'END_STY_FONTAXES_INF'; + if ($seen{Inf}) { + print {$STY} <<'END_STY_FONTAXES_INF'; \fa@naming@exception{figures}{{inferior}{proportional}}{Inf} \fa@naming@exception{figures}{{inferior}{tabular}}{Inf} \def\infigures{\@nomath\infigures \fontfigurestyle{inferior}\selectfont} \DeclareTextFontCommand{\textin}{\infigures} \let\textinferior\textin - + END_STY_FONTAXES_INF } - if ($seen_style{Orn}) { - print {$STYLE} <<'END_STY_FONTAXES_ORN'; + if ($seen{Orn}) { + print {$STY} <<'END_STY_FONTAXES_ORN'; \fa@naming@exception{figures}{{ornament}{proportional}}{Orn} \fa@naming@exception{figures}{{ornament}{tabular}}{Orn} \def\ornaments{\@nomath\ornaments \fontencoding{U}\fontfigurestyle{ornament}\selectfont} \DeclareTextFontCommand{\textornaments}{\ornaments} \providecommand{\ornament}[1]{\textornaments{\char##1}} - + END_STY_FONTAXES_ORN } - if ($seen_style{Numr}) { - print {$STYLE} <<'END_STY_FONTAXES_NUMR'; + if ($seen{Numr}) { + print {$STY} <<'END_STY_FONTAXES_NUMR'; \fa@naming@exception{figures}{{numerators}{proportional}}{Numr} \fa@naming@exception{figures}{{numerators}{tabular}}{Numr} END_STY_FONTAXES_NUMR } - if ($seen_style{Dnom}) { - print {$STYLE} <<'END_STY_FONTAXES_DNOM'; + if ($seen{Dnom}) { + print {$STY} <<'END_STY_FONTAXES_DNOM'; \fa@naming@exception{figures}{{denominators}{proportional}}{Dnom} \fa@naming@exception{figures}{{denominators}{tabular}}{Dnom} END_STY_FONTAXES_DNOM } - print {$STYLE} <<'END_STY_FONTAXES_END'; -}{} - -END_STY_FONTAXES_END + print {$STY} "}{}\n\n"; - print {$STYLE} <<"END_STY_XKEYVAL"; + print {$STY} <<"END_STY_XKEYVAL"; \\IfFileExists{xkeyval.sty}{ - \\newcommand*{\\$safe\@scale}{1} + \\newcommand*{\\$fam\@scale}{1} \\RequirePackage{xkeyval} - \\DeclareOptionX{scaled}{\\renewcommand*{\\$safe\@scale}{##1}} + \\DeclareOptionX{scaled}{\\renewcommand*{\\$fam\@scale}{##1}} }{ \\let\\DeclareOptionX\\DeclareOption \\let\\ExecuteOptionsX\\ExecuteOptions @@ -1002,163 +1115,197 @@ END_STY_FONTAXES_END } END_STY_XKEYVAL - - if ($seen_style{LF} or $seen_style{TLF}) { - print {$STYLE} - "\\DeclareOptionX{lining}{\\edef\\$safe\@figurestyle{LF}}\n"; + + if ($seen{LF} or $seen{TLF}) { + print {$STY} + "\\DeclareOptionX{lining}{\\edef\\$fam\@figurestyle{LF}}\n"; } - if ($seen_style{OsF} or $seen_style{TOsF}) { - print {$STYLE} - "\\DeclareOptionX{oldstyle}{\\edef\\$safe\@figurestyle{OsF}}\n"; + if ($seen{OsF} or $seen{TOsF}) { + print {$STY} + "\\DeclareOptionX{oldstyle}{\\edef\\$fam\@figurestyle{OsF}}\n"; } - if ($seen_style{TLF} or $seen_style{TOsF}) { - print {$STYLE} - "\\DeclareOptionX{tabular}{\\edef\\$safe\@figurealign{T}}\n"; + if ($seen{TLF} or $seen{TOsF}) { + print {$STY} + "\\DeclareOptionX{tabular}{\\edef\\$fam\@figurealign{T}}\n"; } - if ($seen_style{LF} or $seen_style{OsF}) { - print {$STYLE} - "\\DeclareOptionX{proportional}{\\edef\\$safe\@figurealign{}}\n"; + if ($seen{LF} or $seen{OsF}) { + print {$STY} + "\\DeclareOptionX{proportional}{\\edef\\$fam\@figurealign{}}\n"; } - + my $defaults - = $seen_style{OsF} ? 'oldstyle,proportional' - : $seen_style{TOsF} ? 'oldstyle,tabular' - : $seen_style{LF} ? 'lining,proportional' - : $seen_style{TLF} ? 'lining,tabular' - : die "ERROR: encountered un unknown bug"; - + = $seen{OsF} ? 'oldstyle,proportional' + : $seen{TOsF} ? 'oldstyle,tabular' + : $seen{LF} ? 'lining,proportional' + : $seen{TLF} ? 'lining,tabular' + : die "[ERROR] Internal bug, please report!"; + my $default_bold; for my $series ( - qw(ultrablack ultrabold heavy extrablack black + qw(ultrablack ultrabold heavy extrablack black extrabold demibold semibold bold)) { - if ($seen_series{$FD_WEIGHT{$series}}) { - printf {$STYLE} + if ($seen{$FD_WEIGHT{$series}}) { + printf {$STY} "\\DeclareOptionX{%s}{\\renewcommand*{\\bfdefault}{%s}}\n", $series, $FD_WEIGHT{$series}; $default_bold = $series; } } $defaults .= ",$default_bold" if $default_bold; - + my $default_regular; for my $series ( qw(light medium regular)) { - if ($seen_series{$FD_WEIGHT{$series} || 'm'}) { - printf {$STYLE} + if ($seen{$FD_WEIGHT{$series} || 'm'}) { + printf {$STY} "\\DeclareOptionX{%s}{\\renewcommand*{\\mddefault}{%s}}\n", $series, $FD_WEIGHT{$series} || 'm'; $default_regular = $series; } } $defaults .= ",$default_regular" if $default_regular; - - print {$STYLE} <<"END_STYLE_REST"; + + print {$STY} <<"END_STYLE_REST"; \\ExecuteOptionsX{$defaults} \\ProcessOptionsX\\relax \\renewcommand* {\\$ARGV{nfss}default} - {$family-\\$safe\@figurealign\\$safe\@figurestyle} + {$fam-\\$fam\@figurealign\\$fam\@figurestyle} \\renewcommand*{\\familydefault}{\\$ARGV{nfss}default} \\endinput END_STYLE_REST - close $STYLE; + close $STY; + + return; } -# ------------------------------------------------------------------------ +#----------------------------------------------------------------------- +# Walk a nested dictionary, return lookup table with all keys +#----------------------------------------------------------------------- +sub get_keys { + my $dict = shift; + my $seen = shift || {}; + + while (my ($k, $v) = each %$dict) { + $seen->{$k} = 1; + get_keys($v, $seen) if ref $v eq 'HASH'; + } + + return $seen; +} + +#----------------------------------------------------------------------- +# Create a .fd file for LaTeX's NFSS +#----------------------------------------------------------------------- +sub write_fdfile { + my ($fam, $enc, $sty, $data) = @_; + + my $fn = sprintf "%s%s-%s.fd", $enc, $fam, $sty; + my $dir = File::Spec->catdir($ARGV{target}, 'tex', 'latex', $fam); + File::Path::make_path($dir); + $fn = File::Spec->catfile($dir, $fn); + open my $FD, '>', $fn or die "[ERROR] Can't create '$fn': $!"; -sub start_fd_file { - my ($fam, $enc, $fig, $safe) = @_; - - open my $FD, '>', "$enc$fam-$fig.fd" - or die "ERROR: can't create '$enc$fam-$fig.fd' - $!"; - print {$FD} <<"END_FD_HEADER"; -%%Generated by autoinst on $date +%% Generated by autoinst on $TODAY %% -\\ProvidesFile{$enc$fam-$fig.fd} - [$date (autoinst) Font definitions for $enc/$fam-$fig.] +\\ProvidesFile{${enc}${fam}-${sty}.fd} + [$TODAY (autoinst) Font definitions for ${enc}/${fam}-${sty}.] -\\expandafter\\ifx\\csname $safe\@scale\\endcsname\\relax - \\let\\$safe\@\@scale\\\@empty +\\expandafter\\ifx\\csname ${fam}\@scale\\endcsname\\relax + \\let\\${fam}\@\@scale\\\@empty \\else - \\edef\\$safe\@\@scale{s*[\\csname $safe\@scale\\endcsname]}% + \\edef\\${fam}\@\@scale{s*[\\csname ${fam}\@scale\\endcsname]}% \\fi - -\\DeclareFontFamily{$enc}{$fam-$fig}{} + +\\DeclareFontFamily{${enc}}{${fam}-${sty}}{} END_FD_HEADER - return $FD; + while (my ($series, $fdseries) = each %$data) { + while (my ($shape, $fdshape) = each %$fdseries) { + print {$FD} + "\\DeclareFontShape{$enc}{${fam}-${sty}}{$series}{$shape}{\n"; + my @items = sort { $a->[0] <=> $b->[0] } + @{$fdshape}; + $items[0][0] = $items[-1][1] = ''; + $items[$_][0] = $items[$_ - 1][1] for (1 .. $#items); + for my $item (@items) { + print {$FD} " <$item->[0]-$item->[1]>", + " \\${fam}\@\@scale $item->[2]\n"; + } + print {$FD} "}{}\n\n"; + } + } + print {$FD} "\\endinput\n"; + + close $FD; + + return; } -# ------------------------------------------------------------------------ -sub end_fd_file { - my ($FD) = @_; - - print {$FD} "}{}\n\n\\endinput\n"; - close $FD; -} +############################################################################ + +package main; -main() +main(); __END__ - pod2man --center="fontools" --date=`date +"%Y-%m-%d"` \ - --release="fontools" --section=1 autoinst autoinst.1 - - man -t ./autoinst.1 | ps2pdf - autoinst.pdf +############################################################################ + + + To create the documentation: + + pod2man --center="Marc Penninga" --release="fontools" --section=1 \ + autoinst - | groff -Tps -man - | ps2pdf - autoinst.pdf =pod =head1 NAME -autoinst - wrapper script around the F, +autoinst - wrapper around the F, for installing OpenType fonts in LaTeX. =head1 SYNOPSIS -autoinst [options] I [I ...] +B [I] B =head1 DESCRIPTION -Eddie Kohler's F, especially F, are great tools for -installing OpenType fonts for use with LaTeX, but their use (even in -automatic mode) is quite complicated because it needs lots of long -command lines and doesn't generate the F and F files LaTeX needs. -B simplifies the font installation -process by generating and executing all commands for F -and by creating all necessary F and F files. +Eddie Kohler's F, especially F, are superb tools +for installing OpenType fonts in LaTeX, but their use +(even in automatic mode) is complicated: they need many long +command lines and don't generate the F and F files LaTeX needs. +B simplifies the font installation process with F +by generating and executing all command lines +and by creating and installing all F and F files. -All the user then needs -to do is move these files to a suitable location -(F<< $LOCALTEXMF/tex/latex/// >> is the -official choice) and update TeX's filename database. - -Given a family of font files (in either F<.ttf> or F<.otf> format), +Given a family of font files (in either F or F format), B will create several LaTeX font families: =over 2 -=over 2 +=over 3 -=item B<-> +=item - -Four text families (with lining and oldstyle figures, in tabular and +Four text families (with lining and oldstyle digits, in tabular and proportional variants), each with the following shapes: =over 2 -=over 4 +=over 6 =item I @@ -1170,19 +1317,20 @@ Small caps =item I -`Upright swash'; usually normal text with some extra `oldstyle' ligatures, +"Upright swash"; usually normal text with some extra "oldstyle" ligatures, such as ct, sp and st. =item I -Titling shape. Meant for all-caps text only (even though it sometimes contains -lowercase glyphs as well), where letterspacing and the positioning of -punctuation characters have been adjusted to suit all-caps text. -This shape is generated only for the families with lining figures. +Titling shape. Meant for all-caps text only (even though it sometimes contains +lowercase glyphs as well), where letterspacing and the positioning of +punctuation characters have been adjusted to suit all-caps text. +This shape is generated only for the families with lining digits, since +all-caps text doesn't mix with old-style digits. =item I -Italic or oblique text +Italic (or oblique) text =item I @@ -1200,17 +1348,17 @@ Italic titling =back -=item B<-> +=item - -For each text family: a family of TS1-encoded symbol fonts, +For each text family: a family of TS1-encoded symbol fonts, in roman and italic shapes. -=item B<-> +=item - Four families with superiors, inferiors, numerators and denominators, in roman and italic shapes. -=item B<-> +=item - An ornament family, in roman and italic shapes. @@ -1218,12 +1366,12 @@ An ornament family, in roman and italic shapes. =back -Of course, if the font doesn't contain oldstyle figures, small caps etc., -the corresponding shapes or families are not created; -furthermore, the creation of most families and shapes can be controlled by -command-line options (see below). +Of course, if the fonts don't contain oldstyle digits, small caps etc., +the corresponding shapes and families are not created. +Furthermore, the creation of most families and shapes can be controlled by +command-line options (see L below). -The generated font families are named I<< - >>, +The generated font families are named I<< - >>, where I<< >> is one of =over 8 @@ -1246,13 +1394,13 @@ tabular oldstyle figures =item I -superior characters (many fonts only have an incomplete set -of superiors: figures, some punctuation and the letters -I; normal forms will be used for the other characters) +superior characters (many fonts have only an incomplete set of superiors: +digits, punctuation and the letters I; +normal forms will be used for the other characters) =item I -inferior characters; usually only figures and punctuation, +inferior characters; usually only digits and punctuation, normal forms for the other characters =item I @@ -1269,29 +1417,30 @@ denominators =back -The generated fonts are named I<< --- >>, -where I<< >> is the name of the OpenType file, I<< >> -is the same as above (but in lowercase), I<< >> is either empty, -`sc', `swash' or `titling', and I<< >> is the encoding. -A typical name in this scheme is F. +The generated fonts are named I<< --- >>, +where I<< >> is the same as above (but in lowercase), +I<< >> is either empty, "sc", "swash" or "titling", +and I<< >> is the encoding. +A typical name in this scheme would be "MinionPro-Regular-osf-sc-ly1". =head2 On the choice of text encoding -By default, all text families use the LY1 encoding. This has been chosen -over T1 (Cork) because many OpenType fonts contain additional ligatures -such as fj and Th, and LY1 has a number of empty slots to accommodate these. -Different encodings can be selected using the B< --encoding> -command line option (see below). +By default, B generates text fonts with OT1, T1 and LY1 +encodings, and the generated style files use LY1 as the default text encoding. +LY1 has been chosen over T1 because it has some empty slots to accomodate +the additional ligatures and alternate glyphs provided by many OpenType fonts. +Different encodings can be selected using the I<-encoding> +command-line option (see L below). -=head2 Using the fonts with LaTeX +=head2 Using the fonts in your LaTeX documents -B generates a style file for using the font in LaTeX documents, -named `>.sty'. This style file also takes care of loading the +B generates a style file for using the font in LaTeX documents, +named F<< .sty >>. This style file also takes care of loading the F and F packages, if necessary. -To use the font, simply put C<\usepackage{MinionPro}> -(or whatever the font is called) in the preamble of your document. +To use the font, simply put C<<< \usepackage{I<< >>} >>> +in the preamble of your document. This style file defines a number of options: @@ -1299,268 +1448,321 @@ This style file defines a number of options: =item I -Choose which figures will be used for the text fonts. -The defaults are `oldstyle' and `proportional' (if available). +Choose which digits will be used for the text fonts. +The defaults are "oldstyle" and "proportional" (if available). =item I -Choose the weight that LaTeX will use for the `bold' weight +Choose the weight that LaTeX will use for the "bold" weight (i.e., the value of C<\bfdefault>). =item I -Choose the weight that LaTeX will use for the `regular' weight +Choose the weight that LaTeX will use for the "regular" weight (i.e., the value of C<\mddefault>). =item I<< scaled= >> -Scale the font by a factor of I<< >>. +Scale the font by a factor of I<< >>. For example: to increase the size of the font by 5%, use the command -C<\usepackage[scaled=1.05]{MyriadPro}>. +C<<< \usepackage[scaled=1.05]{I<< >>} >>>. This option is only available when the F package is found in your TeX installation. =back -The style file will also try to load the F package (part of -the MinionPro for LaTeX project), which gives easy access to various font -shapes and styles. This package can be downloaded from the project's homepage -(F) or directly through -the CVS web interface -(F), -and is also available from CTAN as part of the archive F -(F). - -Using the machinery set up by F, the generated style file -also defines a few commands (which take the text to be typeset as argument) -and declarations (which don't take arguments, but affect all text up to +The style file will also try to load the F package, +which gives easy access to various font shapes and styles. +It is available from CTAN +(F). +Using the machinery set up by F, the generated style file also +defines a number of commands (which take the text to be typeset as argument) +and declarations (which don't take arguments, but affect all text up to the end of the current group) of its own: DECLARATION COMMAND SHORT FORM OF COMMAND - + \tlshape \texttitling \texttl - \sufigures \textsuperior \textsu - \infigures \textinferior \textin - + \sufigures \textsuperior \textsu + \infigures \textinferior \textin + In addition, the C<\swshape> and C<\textsw> commands are redefined to place -swash on the secondary shape axis (F places it on the primary -shape axis); this allows the use of `upright swash'. -Just saying C<\swshape> will still give normal (italic) swash, -but C<\swshape\upshape> results in upright swash. - -Note that there is no separate command for accessing the italic titling shape; -but these commands behave properly when nested, so C<\tlshape\itshape> gives -italic titling. -There are also no commands for accessing the numerator and denominator -fonts; these can be selected using F' low-level commands, +swash on the secondary shape axis (F places it on the primary +shape axis); this makes these commands behave properly when nested, so that +C<\swshape\upshape> will give upright swash. + +There are no commands for accessing the numerator and denominator +fonts; these can be selected using F' standard commands, e.g., C<\fontfigurestyle{numerator}\selectfont>. -The style file also provides a command C<<< \ornament{I<< >>} >>>, -where C<<< I<< >> >>> is a number from 0 to the total number of -ornaments minus one. Ornaments are always typeset using the current family, +The style file also provides a command C<<< \ornament{I<< >>} >>>, +where C<<< I<< >> >>> is a number from 0 to the total number of +ornaments minus one. Ornaments are always typeset using the current family, series and shape. A list of all ornaments in a font can be created by -running LaTeX on the file F (part of a standard -LaTeX installation) and specifying the ornament font -(e.g., I). +running LaTeX on the file F (part of a standard +LaTeX installation) and supplying the name of the ornament font. + +To access the ornaments, B creates a font-specific encoding file +F<< _orn.enc >>, but only if that file doesn't yet exist. +This means you can provide your own encoding vector, +e.g. if your fonts use non-standard glyph names for ornaments. These commands are only generated for shapes and number styles -that actually exist; no commands are generated for shapes and styles +that actually exist; no commands are generated for shapes and styles that don't exist, or whose generation has been turned off. - -This whole machinery builds on F; if that package cannot be found, -the style file doesn't provide high-level access to the more `exotic' -font shapes and styles. In that case, you're limited to using the lower-level -commands from standard NFSS. +Please note that these commands are built on top of F; +if that package cannot be found, you're limited to using the +lower-level commands from standard NFSS (C<\fontfamily>, C<\fontseries>, +C<\fontshape> etc.). =head2 Using multiple font families in one document -If you want to use several font families in one document, make sure -all fonts were installed using the same version of B. -B has seen some non-backward-compatible changes in the past, -and F<.sty> and F<.fd> files that were generated by different versions -of B may not be able to coexist peacefully. +If you want to use more than one font family in a document, be aware +that style files generated by versions of B older dan 2009 +are incompatible with those generated by newer versions. =head2 NFSS codes -In NFSS, weight and width are concatenated into a single `series' attribute. -B maps widths, weights and shapes to NFSS codes using -the following tables. These are based on the tables in Lehman's -F, but some changes had to be made to avoid -name clashes for font families with many different widths and weights -(such as Helvetica Neue). - - - WEIGHT WIDTH - - Thin t Ultra Condensed uc - Ultra Light ul Extra Condensed ec - Extra Light el Condensed c - Light l Semicondensed sc - Book [1] Regular [1] - Regular [1] Semiextended sx - Medium mb Extended x - Demibold db - Semibold sb - Bold b - Extra Bold eb SHAPES - Black a - Extra Black ea Roman n - Heavy h Italic it - Ultra ub Oblique it [2] - Ultra Bold ub RomanI n [3] - Ultra Black ua RomanII it [3] - +NFSS identifies fonts by a combination of family, series (weight plus width), +shape and size. +B parses the output of C to determine +these parameters. When this fails +(e.g., because the font family contains unusual widths or weights), +B ends up with different fonts having the I values +for the font parameters, which means that these fonts cannot be used in NFSS. +B will then split the font family into multiple subfamilies +(based on the font's "Subfamily" value) and try again. +(Since many font families overdo the "Subfamily" by making each font +a separate subfamily, this strategy is only used as a last resort.) + +If this proliferation of font families is unwanted, +either rerun B on a smaller set of fonts (omitting the ones that +failed to parse correctly) +or else add the missing widths, weights and shapes to the tables C<%FD_WIDTH>, +C<%FD_WEIGHT> and C<%FD_SHAPE>, near the top of the source code. +Please also send a bug report (see L below). + +B maps widths, weights and shapes to NFSS codes using +the following tables. These are based both on the standard I scheme +and on the tables in Philipp Lehman's F, +but some changes had to be made to avoid name clashes in font families +with many different widths and weights. + + + WEIGHT WIDTH + + Thin t Ultra Compressed up + Ultra Light ul Extra Compressed ep + Extra Light el Compressed, Compact p + Light l Compact p + Book [1] Ultra Condensed uc + Regular [1] Extra Condensed ec + Medium mb Condensed c + Demibold db Narrow n + Semibold sb Semicondensed sc + Bold b Regular [1] + Extra Bold eb Semiextended sx + Ultra ub Extended x + Ultra Bold ub Expanded e + Black k Wide w + Extra Black ek + Ultra Black uk + Heavy h SHAPE + Poster r + Roman, Upright n [2] + Italic it + Cursive, Kursiv it + Oblique, Slanted it [3] + Incline(d) it [3] + + +=head3 Notes: =over 4 =item [1] -When I weight and width are empty, the `series' attribute becomes `m'. +When I weight and width are empty, the "series" attribute becomes "m". =item [2] -Mapping the `Oblique' shape to `it' instead of the canonical `sl' simplifies -B. Since font families with both `Italic' and `Oblique' shapes -probably do not exist (apart from Computer Modern), -this shouldn't cause problems in real life. +Adobe Silentium Pro contains two "Roman" shapes ("RomanI" and "RomanII"); +the first of these is mapped to "n", the second one to "it". =item [3] -To the best of my knowledge, the only font family that has two `Roman' shapes -is Silentium; since this has no `Italic' shape, -the `it' code is (ab)used for the `RomanII' shape. +Mapping the "Slanted", "Oblique" or "Inclined" shape to "it" instead of "sl" +simplifies B. Since font families with both italic and slanted +shapes do - to the best of my knowledge - not exist +(apart from Computer Modern, of course), +this shouldn't cause problems in real life. =back - -=head2 A note for MikTeX users -Calling F with the B< --automatic> option (as B does by -default) requires a TeX-installation that uses the F library; with -TeX-installations that implement their own directory searching -(such as MiKTeX) F might complain that it -cannot find a writable F directory and leave all generated F, -F, F and F files in the current working directory. -In that case, you need to move these to their correct destinations. -You also need to tell the dvi-driver (F, F, F etc.) -about the new font map files; see the documentation for how this is done. +=head2 A note for MiKTeX users + +Automatically installing the fonts into a suitable TEXMF tree +(as B does by default) requires a TeX-installation that uses +the F library; with TeX distributions that implement their +own directory searching (such as MiKTeX), B will complain that +it cannot find the F program and install all generated files +into subdirectories of the current directory. +If you use such a TeX distribution, you should either move these files +to their correct destinations by hand, or use the I<-target> option +(see L below) to specify a TEXMF tree. -Also, some OpenType fonts lead to F and F files that are too -big for MiKTeX's F and F; the versions from TeXLive -(F) don't have this -problem. +Also, some OpenType fonts lead to F and F files that +are too big for MiKTeX's F and F; +the versions that come with W32TeX (F) +and TeXLive (F) don't have this problem. =head1 COMMAND-LINE OPTIONS +You may use either one or two dashes before options, +and option names may be shortened to a unique prefix +(e.g., B<-enc> instead of B<-encoding>). + =over 4 -=item B< --encoding>=I +=item B<-encoding>=I + +Use the specified encodings for the text fonts. The default is "OT1,T1,LY1". +For each encoding, a file F<< .enc >> (in all I) +should be somewhere where F can find it. Suitable encoding files +for OT1, T1/TS1 and LY1 come with B. (Note that these files are +called F etc. to avoid name clashes with other packages; +the "fontools_" prefix doesn't need to be specified.) -Use the encoding I for the text fonts. The default is `LY1'. -A file named `>.enc' (in all I) should be somewhere -where F can find it. Suitable encoding files -for LY1, OT1 and T1/TS1 come with I. (Note that these files are -called I to avoid name clashes with other packages; -the `fontools_' prefix doesn't need to be specified.) +Multiple text encodings can be specified as a comma-separated list: +C<-encoding=OT1,T1>. The encodings are passed to F in the order +specified, so the last one will be the default text encoding. -Multiple text encodings can be specified as well: C< --encoding=OT1,T1,LY1>. -The encodings are passed to F in the order specified, -so the last one will be the default text encoding. +=item B<-sanserif> -=item B< --sanserif> +Install the font as a sanserif font, accessed via C<\sffamily> and C<\textsf>. +Note that the generated style file redefines C<\familydefault>, +so including it will still make this font the default text font. -Install the font as a sanserif font, accessed via C<\sffamily> and C<\textsf>. -Note that the generated style file redefines C<\familydefault>, -so including it will make this font the default text font. +=item B<-typewriter> -=item B< --typewriter> +Install the font as a typewriter font, accessed via C<\ttfamily> and +C<\texttt>. +Note that the generated style file redefines C<\familydefault>, +so including it will still make this font the default text font. -Install the font as a typewriter font, accessed via C<\ttfamily> and -C<\texttt>. -Note that the generated style file redefines C<\familydefault>, -so including it will make this font the default text font. +=item B<-ts1> -=item B< --ts1> +=item B<-nots1> -=item B< --nots1> +Turn the creation of TS1-encoded fonts on or off. The default is B<-ts1> +if the text encodings (see I<-encoding> above) include T1, +B<-nots1> otherwise. -Turn the creation of TS1-encoded fonts on or off. The default is B< --ts1> -if the text encodings (see I< --encoding> above) include T1, -B< --nots1> otherwise. +=item B<-smallcaps> -=item B< --smallcaps> +=item B<-nosmallcaps> -=item B< --nosmallcaps> +Turn the creation of small caps fonts on or off. The default is +B<-smallcaps>. -Turn the creation of small caps fonts on or off. The default is -B< --smallcaps>. +=item B<-swash> -=item B< --swash> +=item B<-noswash> -=item B< --noswash> +Turn the creation of swash fonts on or off. The default is B<-swash>. -Turn the creation of swash fonts on or off. The default is B< --swash>. +=item B<-titling> -=item B< --titling> +=item B<-notitling> -=item B< --notitling> +Turn the creation of titling fonts on or off. The default is B<-titling>. -Turn the creation of titling fonts on or off. The default is B< --notitling>. +=item B<-superiors> -=item B< --superiors> +=item B<-nosuperiors> -=item B< --nosuperiors> +Turn the creation of fonts with superior characters on or off. +The default is B<-superiors>. -Turn the creation of fonts with superior characters on or off. -The default is B< --superiors>. +=item B<-inferiors> -=item B< --inferiors> +=item B<-noinferiors> -=item B< --noinferiors> +Turn the creation of fonts with inferior digits on or off. +The default is B<-noinferiors>. -Turn the creation of fonts with inferior figures on or off. -The default is B< --noinferiors>. +=item B<-fractions> -=item B< --fractions> +=item B<-nofractions> -=item B< --nofractions> +Turn the creation of fonts with numerators and denominators on or off. +The default is B<-nofractions>. -Turn the creation of fonts with numerators and denominators on or off. -The default is B< --nofractions>. +=item B<-ornaments> -=item B< --ornaments> +=item B<-noornaments> -=item B< --noornaments> +Turn the creation of ornament fonts on or off. The default is B<-ornaments>. -Turn the creation of ornament fonts on or off. The default is B< --ornaments>. +=item B<-target>=I -=item B< --manual> +Install all generated files into the TEXMF tree at I. -Manual mode. By default, B immediately executes all F -command lines it generates; with the B< --manual> option, these commands are -instead written to a batch command file (named `>.bat', to make things -easier for our friends on Windows). Also, the generated F command -lines specify the I< --pl> option and leave out the I< --automatic> option; -this causes human readable (and editable) F and F files to be created -instead of the default F and F files. +By default, B searches your $TEXMFLOCAL and $TEXMFHOME paths +and installs all files into subdirectories of the first writable TEXMF tree +it finds (or into subdirectories of the current directory, +if no writable directory is found). -=item B< --verbose> +B: this option gets overriden by the B<-manual> option! + +=item B<-manual> + +Manual mode. By default, B immediately executes all F +command lines it generates; with the B<-manual> option, these commands are +instead written to a file F. +Also, the generated F command lines specify the I< --pl> option +(which tells F to generate readable/editable F and F files +instead of the default F and F files) +and leave out the I< --automatic> option (which tells F to +leave all generated files in the current directory, rather than install +them into your TEXMF tree). + +When using this option, you should run F and F after +executing all commands, +to convert the F and F files to F and F format. + +B: this option overrides the B<-target> option! + +=item B<-verbose> Verbose mode; print detailed info about what B thinks it's doing. -=item B< --extra>=I +=item B<-extra>=I -Pass I as options to I. To prevent I from accidentily +Pass I as options to I. To prevent I from accidentily being interpreted as options to B, it should be properly quoted. +=item B<-figurekern> + +=item B<-nofigurekern> + +Some fonts provide kerning pairs for tabular figures. +This is probably unwanted (e.g., numbers in tables won't line up exactly). +The option B<-nofigurekern> adds extra I< --ligkern> options +to the command lines for I to suppress such kerns +(but only for the "TLF" and "TOsF" families). +Since this leads to very long command lines (it adds one hundred such options) +and the problem affects only few fonts, the default is B<-figurekern>. + =back @@ -1568,52 +1770,48 @@ being interpreted as options to B, it should be properly quoted. Eddie Kohler's TypeTools (F). -Perl is usually pre-installed on Linux and Unix systems; -on Windows, try ActivePerl (available from F) -or Strawberry Perl (F). +Perl is pre-installed on most Linux and Unix systems; +on Windows, try ActiveState's ActivePerl +(available from F) +or Strawberry Perl (F). -XeTeX (F) is an extension of TeX -that can natively use any font installed in the operating system -(including both flavours of OpenType fonts) -without additional support files. +XeTeX (F) and LuaTeX (F) +are TeX extensions that can use any font (including both flavours of OpenType) +without TeX-specific support files. -John Owens' F (available from CTAN) is another wrapper +John Owens' F (available from CTAN) is another wrapper around F, and may work when B doesn't. -The MinionPro for LaTeX project -(F, also on CTAN) -developed very complete support files for Minion Pro (including math), +The MinionPro for LaTeX project +(F, also on CTAN) +developed very complete support files for Minion Pro (including math), but the project appears to have been abandoned; -these files don't work with recent versions of Minion Pro. +these files don't work with the latest versions of Minion Pro. =head1 AUTHOR -Marc Penninga - -When sending a bug report, please give as much relevant information as -possible; this usually includes (but may not be limited to) the output from -running B with the B< --verbose> option. -Please make sure that this output includes all error messages (if any); -this can be done using the command +Marc Penninga -C<< autoinst I<(... all options and files ...)> Eautoinst.log 2>&1 >> +When sending a bug report, please give as much relevant information as +possible; this includes at least (but may not be limited to) the output +from running B with the I<-verbose> option. +Please make sure that this output includes all (if any) error messages. =head1 COPYRIGHT -Copyright (C) 2005, 2006, 2007, 2009, 2010, 2011 Marc Penninga. +Copyright (C) 2005-2012 Marc Penninga. =head1 LICENSE This program is free software; you can redistribute it and/or modify -it under the terms of the GNU General Public License -as published by the Free Software Foundation, -either version 2 of the License, or (at your option) -any later version. -A copy of the GNU General Public License is included with the I -collection; see the file F. +it under the terms of the GNU General Public License as published +by the Free Software Foundation, either version 2 of the License, +or (at your option) any later version. +A copy of the GNU General Public License is included with B; +see the file F. =head1 DISCLAIMER @@ -1627,36 +1825,60 @@ GNU General Public License for more details. =head1 RECENT CHANGES -(See the source code for the full story.) +(See the source code for the rest of the story.) =over 12 +=item I<2012-03-06> + +Implemented the "splitting the font family into multiple subfamilies" +emergency strategy when font info parsing fails. +Added recognition for a number of unusual widths, weights and shapes. + +=item I<2012-02-29> + +Fixed a bug in the font parsing code, +where possible widths, weights and shapes where tested in the wrong order; +this led to "ExtraLight" fonts being recognised as "Light". +Added recognition for "Narrow" and "Wide" widths. +Also added the I<-(no)figurekern> command-line option. + +=item I<2012-02-01> + +Reorganised the code, and fixed some bugs in the process. +Added the I<-target> command-line option. +Made B install the F and F files in +the same TEXMF tree as the other generated files. +Generate OT1, T1 and LY1 encoded text fonts by default. +Made I<-titling> a default option (instead of I<-notitling>). +Updated the documentation. + =item I<2011-06-15> Fixed the font info parsing code for some fonts that are -too lazy to spell out 'Italic' in full. +too lazy to spell out "Italic" in full. =item I<2010-04-29> -The C< --feature=kern> option is only used for fonts that +The I< --feature=kern> option is only used for fonts that contain either a I feature or a I table. -Font feature selection commands in the F<.sty> file are only -generated for shapes and figure styles that are supported +Font feature selection commands in the F file are only +generated for shapes and figure styles that are supported by the current font, and whose generation has not been -turned off using the command line options. +turned off using the command-line options. Fixed the font info parsing to work with the Condensed fonts in the Minion Pro family. =item I<2010-04-23> -Always provide the C< --feature=kern> option to F, -even if the font doesn't have a I feature; +Always provide the I< --feature=kern> option to F, +even if the font doesn't have a I feature; this will make F use the I table if present. -For fonts without a I feature, add C< --ligkern> +For fonts without a I feature, add I< --ligkern> options for the common f-ligatures to the F command line, so that any ligatures present in the font will still be used. -Bug fix: the generated F<.sty> files now work for font families -with names containing digits. +Bug fix: the generated F files now work for font families +with names containing digits. =item I<2009-04-09> @@ -1665,13 +1887,16 @@ I, to prevent name clashes with other packages. =item I<2009-04-06> -A small patch to the C subroutine; -it now also recognises the I ornament glyphs -in Adobe's Kepler Pro. +A small patch to the C subroutine: +it now also recognises the I ornament glyphs +in Adobe Kepler Pro. + +=back =begin Really_old_history +=over 12 =item I<2007-08-07> @@ -1680,17 +1905,17 @@ Fixed a small bug with filename quoting on Windows. =item I<2007-07-31> Changed the tables that map weights and widths to NFSS codes: -in some extended families (Helvetica Neue), different combinations of -weight and width were mapped to the same `series'. +in some extended families, different combinations of +weight and width were mapped to the same series. Added a work-around for incorrect size info in some Kepler fonts. -Fixed a small bug in the generated commands for otftotfm -(sometimes, the I< --onum> feature was included twice). +Fixed a small bug in the generated commands for otftotfm +(sometimes, the "onum" feature was included twice). Added encoding file for OT1 to the I collection. =item I<2007-07-27> -Two bugfixes: a closing brace was missing in the generated style file, -and the NFSS series was formed as `width plus weight' instead of the reverse. +Two bugfixes: a closing brace was missing in the generated style file, +and the NFSS series was formed as "width plus weight" instead of the reverse. =item I<2007-06-10> @@ -1700,92 +1925,92 @@ caused problems for some other packages. =item I<2007-06-04> -Added the F< --no-updmap> option to all generated commands for F +Added the I< --no-updmap> option to all generated commands for F (except the last); this should yield a significant speed-up for large families (suggested by Steven E. Harris). Tweaked the font info parsing to work around a bug in the naming of some FontFont fonts, where every font is in a family of its own. -Added the `scaled' option (including the loading of F) +Added the "scaled" option (including the loading of F) to the generated style file. -Extended the output of the F< --verbose> option. +Extended the output of the I<-verbose> option. =item I<2007-02-08> -Yet Another Complete Rewrite. -The code is now much more readable and more flexible; +Yet Another Complete Rewrite. +The code is now much more readable and more flexible; the program can now handle fonts from different families, -as well as multiple text encodings. +as well as multiple text encodings. Rewrote the font info parsing code to work for Arno Pro. =item I<2006-10-11> The program determines the fonts' weights, widths and shapes by parsing -the output from F instead of the font filename. -This should make B work for non-Adobe fonts. +the output from C instead of the font filename. +This should make B work for non-Adobe fonts. Filenames with spaces now work as well. =item I<2006-08-31> -Made the generated style files try to include `fontaxes.sty'; -changed the names of the generated fonts and families +Made the generated style files try to include "fontaxes.sty"; +changed the names of the generated fonts and families (to make the previous change possible); -added command line options for most font styles and shapes; +added command-line options for most font styles and shapes; tweaked the filename parsing code for Cronos Pro and Gill Sans Pro; added runtime generation of encoding vectors for ornament fonts (because GaramondPremier's ornament names differ from other fonts); -changed the NFSS-code for italic small caps and titling to `scit' and `tlit' -(to work with F); +changed the NFSS-code for italic small caps and titling to "scit" and "tlit" +(to work with F); and edited (and hopefully improved) the documentation. =item I<2005-10-03> -When creating LY1, T1, OT1 or TS1 encoded fonts, the I< --coding-scheme> -option is added to the commands for F; this should make the +When creating LY1, T1, OT1 or TS1 encoded fonts, the I<-coding-scheme> +option is added to the commands for F; this should make the generated F and F files acceptable to I. Also elaborated the documentation somewhat and fixed a small bug. =item I<2005-09-22> -Added check to see if filename parsing succeeded; -updated the filename parsing code to cater for GaramondPremier, Silentium +Added check to see if filename parsing succeeded; +updated the filename parsing code to cater for GaramondPremier, Silentium and some non-Adobe fonts; -added the B< --sanserif> and B< --typewriter> options and hacked the +added the I<-sanserif> and I<-typewriter> options and hacked the style files to support using several different font families in one document. =item I<2005-09-12> Cleaned up the code (it now runs under the F and F pragmas); -fixed a (rather obscure) bug that occurred when creating TS1-encoded -fonts for families with multiple optical masters and oldstyle figures; +fixed a (rather obscure) bug that occurred when creating TS1-encoded +fonts for families with multiple optical masters and oldstyle digits; added the I etc. options to the style file; and improved the layout of the generated files. =item I<2005-08-11> The generated commands weren't actually executed, only printed.... -Also added a small hack to cater for fonts -(such as some recent versions of MinionPro) -that contain swash characters but don't provide a `swsh' feature. +Also added a small hack to cater for fonts +(such as some recent versions of MinionPro) +that contain swash characters but don't provide a "swsh" feature. =item I<2005-08-10> -Dropped the `fontname' scheme in favor of a more verbose naming scheme, -since many filenames were still more than eight characters long anyway. +Dropped the "fontname" scheme in favor of a more verbose naming scheme, +since many filenames were still more than eight characters long anyway. Added F-like commands to the generated style file. -Changed the default encoding to LY1 and added the `inferior' shape. +Changed the default encoding to LY1 and added the "inferior" shape. =item I<2005-08-01> -Rewrote (and hopefully improved) the user interface; -changed the program to by default execute the generated F command -lines rather than writing them to a file; -added automatic determination of the `fontname' code for the font family; -changed the NFSS code for italic small caps to `si'; added titling shapes; -changed the generated style -file to include an interface for the ornaments and to load Lehman's NFSS -extensions F if this is installed; corrected the `fontname' codes +Rewrote (and hopefully improved) the user interface; +changed the program to by default execute the generated F command +lines rather than writing them to a file; +added automatic determination of the "fontname" code for the font family; +changed the NFSS code for italic small caps to "si"; added titling shapes; +changed the generated style +file to include an interface for the ornaments and to load Lehman's NFSS +extensions F if this is installed; corrected the "fontname" codes for OT1, T1, LY1 and user-specific encodings; extended the output generated by -the B< --verbose> option; and rewrote and extended the documentation. +the I<-verbose> option; and rewrote and extended the documentation. =item I<2005-06-16> diff --git a/Build/source/texk/texlive/linked_scripts/fontools/cmap2enc b/Build/source/texk/texlive/linked_scripts/fontools/cmap2enc deleted file mode 100755 index 4ba6842e179..00000000000 --- a/Build/source/texk/texlive/linked_scripts/fontools/cmap2enc +++ /dev/null @@ -1,5307 +0,0 @@ -#!/usr/bin/perl - -=begin COPYRIGHT ------------------------------------------------------------ - - cmap2enc - convert glyph indices in a TrueType-flavored OpenType font to - Adobe glyph names - - Copyright (c) 2005, 2006 Marc Penninga. - - This program is free software; you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to - - Free Software Foundation, Inc., - 59 Temple Place, - Suite 330, - Boston, MA 02111-1307, - USA - -=end ------------------------------------------------------------------------ - -=cut - -use Getopt::Std; -use integer; -use warnings; no warnings qw(uninitialized); - -%friendly_name = ( - aalt => "Access All Alternates", - afrc => "Alternate Fractions", - alts => "Alternate Forms", - calt => "Contextual Alternates", - case => "Case-Sensitive Forms", - clig => "Contextual Ligatures", - cpsp => "Capital Spacing", - cswh => "Contextual Swash", - c2sc => "Small Capitals From Capitals", - dlig => "Discretionary Ligatures", - dnom => "Denominators", - expt => "Expert Forms", - fina => "Terminal Forms", - frac => "Fractions", - hist => "Historical Forms", - hlig => "Historical Ligatures", - init => "Initial Forms", - liga => "Standard Ligatures", - lnum => "Lining Figures", - numr => "Numerators", - onum => "Oldstyle Figures", - ordn => "Ordinals", - ornm => "Ornaments", - pnum => "Proportional Figures", - rlig => "Required Ligatures", - salt => "Stylistic Alternates", - sinf => "Scientific Inferiors", - smcp => "Small Caps", - subs => "Subscripts", - sups => "Superscripts", - swsh => "Swash", - titl => "Titling", - tnum => "Tabular Figures", - zero => "Slashed Zero", -); - -sub getu($) { - my $arg = shift; - my $n = length $arg; - my $r = 0; - - for my $i (0 .. $n - 1) { - $r = ($r << 8) + unpack("C", substr($arg, $i, 1)); - } - - return $r; -} - -sub getcov($) { - my $Coverage = shift; - my $CoverageFormat = getu(substr $Coverage, 0, 2); - my @r = (); - if ($CoverageFormat == 1) { - my $GlyphCount = getu(substr $Coverage, 2, 2); - for my $i (0 .. $GlyphCount - 1) { - push @r, getu(substr $Coverage, 4 + 2 * $i, 2); - } - } elsif ($CoverageFormat == 2) { - my $RangeCount = getu(substr $Coverage, 2, 2); - for my $i (0 .. $RangeCount - 1) { - my $RangeRecord = substr $Coverage, 4 + 6 * $i, 6; - my $Start = getu(substr $RangeRecord, 0, 2); - my $End = getu(substr $RangeRecord, 2, 2); - for my $j ($Start .. $End) { - push @r, $j; - } - } - } else { - warn "Warning: unknown CoverageFormat `$CoverageFormat'\n"; - } - return @r; -} - - -############################################################################## - - -getopts "f:l:ps:x:", \%options; -if ($options{f}) { - for (split ",", $options{f}) { - $feature_selected{$_} = 1; - } -} -$suffix = $feature_selected{ pnum } ? '-' : '-t'; -$suffix .= $feature_selected{ onum } ? 'osf' : 'lf'; -$suffix .= $feature_selected{ smcp } ? '-sc' : ''; -$suffix .= $feature_selected{ swsh } ? '-swash' : ''; -$suffix .= $feature_selected{ titl } ? '-titling' : ''; - -if ( $feature_selected{ sups } ) { $suffix = '-sup' } -if ( $feature_selected{ ornm } ) { $suffix = '-orn' } - -$options{s} ||= "latn"; -$options{l} ||= "DFLT"; - -$0 =~ s!.*/!!; -die "Usage: $0 [options] fontfile encfile\n" - unless ($options{p} and @ARGV == 1) or @ARGV == 2; - -chop(@glyph = ); -for (@glyph) { - next if /^\s*\#/; - /(.+);([\dA-Fa-f]{4})/ and $code{$1} = $2; -} - -if ((chop($fn = `kpsewhich $ARGV[0] 2>&1`) and -e $fn) or - (chop($fn = `findtexmf $ARGV[0] 2>&1`) and -e $fn)) -{ - open FONT, "<$fn" or die "Error: can't open `$fn' - $!\n"; -} else { - open FONT, "<$ARGV[0]" or - die "Error: can't open `$ARGV[0]' - $!\n"; -} -binmode FONT; -{ - local $/; - $font = ; -} - -$OffsetTable = substr $font, 0, 12; -$numTables = getu(substr $OffsetTable, 4, 2); - -$TableDirectory = substr $font, 12, 16 * $numTables; -for $i (0 .. $numTables - 1) { - $entry = substr $TableDirectory, 16 * $i, 16; - - $tag = substr $entry, 0, 4; - $offset{$tag} = getu(substr $entry, 8, 4); - $length{$tag} = getu(substr $entry, 12, 4); -} - -if (exists $offset{GSUB}) { - $GSUB = substr $font, $offset{GSUB}, $length{GSUB}; - $ScriptList = substr $GSUB, getu(substr $GSUB, 4, 2); - $FeatureList = substr $GSUB, getu(substr $GSUB, 6, 2); - $LookupList = substr $GSUB, getu(substr $GSUB, 8, 2); - - $LookupCount = getu(substr $LookupList, 0, 2); - undef @Lookup; - undef @LookupType; - for $i (0 .. $LookupCount - 1) { - $Lookup = substr $LookupList, getu(substr $LookupList, 2 + 2 * $i, 2); - $LookupType[$i] = getu(substr $Lookup, 0, 2); - next unless $LookupType[$i] == 1; - $SubTableCount = getu(substr $Lookup, 4, 2); - for $j (0 .. $SubTableCount - 1) { - $SubTable = substr $Lookup, getu(substr $Lookup, 6 + 2 * $j, 2); - $SubstFormat = getu(substr $SubTable, 0, 2); - if ($SubstFormat == 1) { - $Coverage = substr $SubTable, getu(substr $SubTable, 2, 2); - @Coverage = getcov($Coverage); - $DeltaGlyphID = getu(substr $SubTable, 4, 2); - for $k (0 .. $#Coverage) { - $Lookup[$i]{$Coverage[$k]} = $Coverage[$k] + $DeltaGlyphID; - } - } elsif ($SubstFormat == 2) { - $Coverage = substr $SubTable, getu(substr $SubTable, 2, 2); - @Coverage = getcov($Coverage); - $GlyphCount = getu(substr $SubTable, 4, 2); - if ($GlyphCount != scalar(@Coverage)) { - warn "Error: SingleSubstFormat2 subtable - " . - "GlyphCount wrong\n"; - next; - } - for $k (0 .. $#Coverage) { - $Lookup[$i]{$Coverage[$k]} = - getu(substr $SubTable, 6 + 2 * $k, 2); - } - } else { - warn "Error: unknown SingleSubstFormat `$SubstFormat'\n"; - next; - } - } - } - - undef @FeatureTag; - undef @FeatureLookupListIndex; - $FeatureCount = getu(substr $FeatureList, 0, 2); - for $i (0 .. $FeatureCount - 1) { - $FeatureRecord = substr $FeatureList, 2 + 6 * $i, 6; - $FeatureTag[$i] = substr $FeatureRecord, 0, 4; - $Feature = substr $FeatureList, getu(substr $FeatureRecord, 4, 2); - $LookupCount = getu(substr $Feature, 2, 2); - $feature_supported{$FeatureTag[$i]} = 1; - for $j (0 .. $LookupCount - 1) { - $FeatureLookupListIndex[$i][$j] = - getu(substr $Feature, 4 + 2 * $j, 2); - if ($LookupType[$FeatureLookupListIndex[$i][$j]] != 1) { - $feature_supported{$FeatureTag[$i]} = 0; - } - } - } - - undef %Script; - undef %FeatureIndex; - $ScriptCount = getu(substr $ScriptList, 0, 2); - for $i (0 .. $ScriptCount - 1) { - $ScriptRecord = substr $ScriptList, 2 + 6 * $i, 6; - $ScriptTag = substr $ScriptRecord, 0, 4; - $Script = substr $ScriptList, getu(substr $ScriptRecord, 4, 2); - if (substr($Script, 0, 2)) { - $LangSysTag = "DFLT"; - push @{$Script{$ScriptTag}}, $LangSysTag; - $LangSys = substr $Script, getu(substr $Script, 0, 2); - $FeatureCount = getu(substr $LangSys, 4, 2); - for $k (0 .. $FeatureCount - 1) { - push @{$FeatureIndex{$ScriptTag}{$LangSysTag}}, - getu(substr $LangSys, 6 + 2 * $k, 2); - } - } - $LangSysCount = getu(substr $Script, 2, 2); - for $j (0 .. $LangSysCount - 1) { - $LangSysRecord = substr $Script, 4 + 6 * $j, 6; - $LangSysTag = substr $LangSysRecord, 0, 4; - push @{$Script{$ScriptTag}}, $LangSysTag; - $LangSys = substr $Script, getu(substr $LangSysRecord, 4, 2); - $FeatureCount = getu(substr $LangSys, 4, 2); - for $k (0 .. $FeatureCount - 1) { - push @{$FeatureIndex{$ScriptTag}{$LangSysTag}}, - getu(substr $LangSys, 6 + 2 * $k, 2); - } - } - } -} - -if (exists $offset{GPOS}) { - $GPOS = substr $font, $offset{GPOS}, $length{GPOS}; - $FeatureList = substr $GPOS, getu(substr $GPOS, 6, 2); - $FeatureCount = getu(substr $FeatureList, 0, 2); - for $i (0 .. $FeatureCount - 1) { - $FeatureRecord = substr $FeatureList, 2 + 6 * $i, 6; - $FeatureTag = substr $FeatureRecord, 0, 4; - $feature_supported{$FeatureTag} = 0; - } -} - -if ($options{p}) { - if (exists $offset{name}) { - $name = substr $font, $offset{name}, $length{name}; - $count = getu(substr $name, 2, 2); - $stringOffset = getu(substr $name, 4, 2); - for $i (0 .. $count - 1) { - $nameRecord = substr $name, 6 + 12 * $i, 12; - $platformID = getu(substr $nameRecord, 0, 2); - $encodingID = getu(substr $nameRecord, 2, 2); - $languageID = getu(substr $nameRecord, 4, 2); - $nameID = getu(substr $nameRecord, 6, 2); - $length = getu(substr $nameRecord, 8, 2); - $offset = getu(substr $nameRecord, 10, 2); - $string = substr $name, $stringOffset + $offset, $length; - $string{"$platformID,$encodingID,$languageID,$nameID"} = $string; - } - print "\n", "-" x 80, "\n\n"; - for $i ((6,10,0)) { - if (exists $string{"0,3,0,$i"}) { - print $string{"0,3,0,$i"}, "\n\n"; - } elsif (exists $string{"0,4,0,$i"}) { - print $string{"0,4,0,$i"}, "\n\n"; - } elsif (exists $string{"3,1,1033,$i"}) { - print $string{"3,1,1033,$i"}, "\n\n"; - } elsif (exists $string{"3,10,1033,$i"}) { - print $string{"3,10,1033,$i"}, "\n\n"; - } - } - print "-" x 80, "\n\n"; - } - print "SCRIPT\tLANG\tFEATURES\n\n"; - for $script (keys %Script) { - print "$script"; - for $lang (@{$Script{$script}}) { - print "\t$lang\t"; - for (sort {$a <=> $b} @{$FeatureIndex{$script}{$lang}}) { - print "$FeatureTag[$_]", - exists $friendly_name{$FeatureTag[$_]} - ? " - $friendly_name{$FeatureTag[$_]}" - : " - Unknown Feature", - $feature_supported{$FeatureTag[$_]} - ? "" - : " (not supported by $0)", - "\n\t\t"; - } - print "\n"; - } - } - print "-" x 80, "\n\n"; -} - -undef @subst; -for $i (0 .. 0xFFFF) { - $subst[$i] = $i; -} - -undef %lookup_selected; -for $feature (sort {$a <=> $b} @{$FeatureIndex{$options{s}}{$options{l}}}) { - if (!$feature_selected{$FeatureTag[$feature]}) { - next; - } - if (!$feature_supported{$FeatureTag[$feature]}) { - warn "Warning: feature `$FeatureTag[$feature]' not supported\n"; - next; - } - for (@{$FeatureLookupListIndex[$feature]}) { - $lookup_selected{$_} = 1; - } -} -for $lookup (sort {$a <=> $b} keys %lookup_selected) { - for (sort {$a <=> $b} keys %{$Lookup[$lookup]}) { - $subst[$_] = $Lookup[$lookup]{$_}; - } -} - -if ($options{x}) { - open SUB, "<$options{x}" - or warn "Warning: can't open `$options{x}' - $!\n\tfile skipped\n"; - for () { - if (/^\s*\#/) { - next; - } elsif (/([0-9A-Fa-f]{4});([0-9A-Fa-f]{4})/) { - $subst[hex($1)] = hex($2); - $subst[hex($2)] = hex($2); - } elsif (/(\w+);([0-9A-Fa-f]{4})/) { - $glyphName{$1} ||= sprintf - hex($2) < 256 ? "index0x%02X" : "index0x%04X", hex $2; - delete $code{$1}; - $subst[hex($2)] = hex($2); - } - } -} - -$cmap = substr $font, $offset{cmap}, $length{cmap}; -$numTables = getu(substr $cmap, 2, 2); - -for $i (0 .. $numTables - 1) { - $EncodingRecord = substr $cmap, 4 + $i * 8, 8; - $platformID = getu(substr $EncodingRecord, 0, 2); - $encodingID = getu(substr $EncodingRecord, 2, 2); - $offset = getu(substr $EncodingRecord, 4, 4); - $format = getu(substr $cmap, $offset, 2); - $length = getu(substr $cmap, $offset + 2, 2); - $subtable = substr $cmap, $offset, $length; - - next unless ($platformID == 0 and ($encodingID == 3 or $encodingID == 4)) - or ($platformID == 3 and ($encodingID == 1 or $encodingID == 10)); - - if ($format == 4) { - $segCountX2 = getu(substr $subtable, 6, 2); - $segCount = $segCountX2 / 2; - - $endCount = substr $subtable, 14, $segCountX2; - $startCount = substr $subtable, 16 + $segCountX2, $segCountX2; - $idDelta = substr $subtable, 16 + 2 * $segCountX2, $segCountX2; - $idRangeOffset = substr $subtable, 16 + 3 * $segCountX2, $segCountX2; - - for $j (0 .. $segCount - 1) { - $endCount[$j] = getu(substr $endCount, 2 * $j, 2); - $startCount[$j] = getu(substr $startCount, 2 * $j, 2); - $idDelta[$j] = getu(substr $idDelta, 2 * $j, 2); - $idRangeOffset[$j] = getu(substr $idRangeOffset, 2 * $j, 2); - - next if $startCount[$j] == 0xFFFF; - - for $characterCode ($startCount[$j] .. $endCount[$j]) { - if ($idRangeOffset[$j] != 0) { - $ptr = $idRangeOffset[$j] / 2 - + $characterCode - $startCount[$j] - + 8 + 3 * $segCount - + $j; - $tmp = getu(substr $subtable, 2 * $ptr, 2); - if ($tmp) { - $glyphIndex = ($tmp + $idDelta[$j]) % 65536; - } else { - $glyphIndex = 0; - } - } else { - $glyphIndex = ($characterCode + $idDelta[$j]) % 65536; - } - $glyphIndex = $subst[$glyphIndex]; - $uni = sprintf "%04X", $characterCode; - $glyphName{$uni} ||= sprintf - $glyphIndex < 256 ? "index0x%02X" : "index0x%04X", - $glyphIndex; - } - } - last; - } else { - warn "Warning: unsupported format `$format'\n"; - } -} -if (!keys %glyphName) { - die "Error: no supported platformID/encodingID found in `cmap' table\n"; -} - -if (!$options{p}) { - if ((chop($fn = `kpsewhich $ARGV[1] 2>&1`) and -e $fn) or - (chop($fn = `findtexmf $ARGV[1] 2>&1`) and -e $fn)) - { - open ENC, "<$fn" or die "Error: can't open `$fn' - $!\n"; - } else { - open ENC, "<$ARGV[1]" or die "Error: can't open `$ARGV[1]' - $!\n"; - } - chop(@lines = ); - map s/%.+//, @lines; - $_ = join "", @lines; - ($name, $_) = /\/([\w-]+)\s*\[(.*)\]\s*def/; - @vector = /([\w.]+)/g; - - $ARGV[0] =~ /(.+)\.(?:ttf|otf)/ and $fontname = $1; - $ARGV[1] =~ /(.+)\.enc/ and $encname = $1; - open ENC, ">${encname}${suffix}-${fontname}.enc" or die - "Error: can't open `${encname}${suffix}-${fontname}.enc' - $!\n"; - print ENC "/${name}${suffix}-${fontname} [\n"; - for ($i = 0; $i < 256; $i += 16) { - printf ENC "%% 0x%04x\n", $i; - for ($j = 0; $j < 16; $j += 4) { - for $k (0 .. 3) { - print ENC " /", - $glyphName{$code{$vector[$i + $j + $k]}} || - $glyphName{$vector[$i + $j + $k]} || - $vector[$i + $j + $k]; - } - print ENC "\n"; - } - } - print ENC "] def\n"; - - open MTX, ">reset${fontname}-${encname}${suffix}.mtx" - or die "Error: can't open " . - "'reset${fontname}-${encname}${suffix}.mtx' - $!\n"; - print MTX < I - - -=head1 DESCRIPTION - -Many TrueType-flavored OpenType fonts contain no glyph names. -When creating an F file with F, this causes all glyphs to be -named something -like C, which makes the F file almost useless for use with -F or F. - -B uses the font's `cmap' table to map glyph indices to -Unicode values, and Adobe's F file to map these to glyph names. - -B creates a new encoding file (for downloading with the font file) -and a F file (for use with F). The encoding file contains the -same glyphs as the original one, but has all glyph names replaced with -the corresponding glyph indices; the F file maps these glyph indices back -to the original glyph names (it consists of many commands of the form -C<\renameGlyph{index0x01E7}{Euro}>, plus a definition of that -C<\renameGlyph> command). - -Some of the glyph substitution features of OpenType fonts are supported; -e.g. when the `smcp' (Small Caps) feature is specified, the glyph names -of the lowercase glyphs will be mapped to the glyph indices of the -small capitals. - -A list of features supported by the font can be generated using the B<-p> -option, see below. - - -=head1 EXAMPLES - -NOTE: the F subdirectory in the I distribution contains -several complete examples of the use of B and other tools from -the I collection. - -=over 2 - -=item B<-> - -To display all scripts, languages and features supported by Linotype Palatino: - - cmap2enc -p pala.ttf - - -=item B<-> - -To install Linotype Palatino in T1 encoding, with oldstyle figures: - -=over 3 - -=item B<1.> - -Generate an encoding file F and a metrics file -F: - - cmap2enc -f onum pala.ttf t1.enc - - -=item B<2.> - -Create an F file for the font; this is done best using I -(also in the I collection): - - font2afm pala.ttf - - -=item B<3.> - -Reencode the F file using the F encoding to create -a `raw' font I, with either I (also in the I -collection) or I (but be warned that I might take a long -time, and can even crash if the F is really big): - - afm2afm -e t1-tosf-pala.enc -o rlplrj9d.afm pala.afm - -or - - \transformfont{rlplrj9d}{\reencodefont{t1-tosf-pala}{\fromafm{pala}}} - - -=item B<4.> - -Create a `value-added' F file from this raw font by adding -ligatures, faking missing glyphs etc. with I: - - \installfont{lplrj9d}{rlplrj9d,resetpala-t1-tosf,newlatin} - {t1}{T1}{lplj}{m}{n}{} - - -=back - -=back - - -=head1 OPTIONS - -B supports the following command-line options: - -=over 4 - -=item B<-p> - -Print some info about the font, plus a list of all scripts, languages and -features contained in this font's GSUB table; then exit. (When using -this option, the I need not be specified.) - -=item B<-f> I[,I]* - -Use the specified features when matching glyph indices to glyph names. -Multiple features can be specified as a comma-separated list, -B spaces between the items. - -=item B<-x> I - -Use the user-specified substitutions from I (see below). - -=item B<-l> I - -Select the specified language. The default is `DFLT' (surprise!). - -=item B<-s> I