r1967 - in packages/libfont-ttf-perl/trunk: . debian lib
lib/Font/TTF lib/Font/TTF/Kern lib/Font/TTF/Mort
Russ Allbery
rra at costa.debian.org
Tue Jan 17 03:08:00 UTC 2006
Author: rra
Date: 2006-01-17 03:07:20 +0000 (Tue, 17 Jan 2006)
New Revision: 1967
Modified:
packages/libfont-ttf-perl/trunk/META.yml
packages/libfont-ttf-perl/trunk/debian/changelog
packages/libfont-ttf-perl/trunk/lib/Font/TTF/AATKern.pm
packages/libfont-ttf-perl/trunk/lib/Font/TTF/AATutils.pm
packages/libfont-ttf-perl/trunk/lib/Font/TTF/Anchor.pm
packages/libfont-ttf-perl/trunk/lib/Font/TTF/Bsln.pm
packages/libfont-ttf-perl/trunk/lib/Font/TTF/Cmap.pm
packages/libfont-ttf-perl/trunk/lib/Font/TTF/Coverage.pm
packages/libfont-ttf-perl/trunk/lib/Font/TTF/Cvt_.pm
packages/libfont-ttf-perl/trunk/lib/Font/TTF/Delta.pm
packages/libfont-ttf-perl/trunk/lib/Font/TTF/Fdsc.pm
packages/libfont-ttf-perl/trunk/lib/Font/TTF/Feat.pm
packages/libfont-ttf-perl/trunk/lib/Font/TTF/Fmtx.pm
packages/libfont-ttf-perl/trunk/lib/Font/TTF/Font.pm
packages/libfont-ttf-perl/trunk/lib/Font/TTF/Fpgm.pm
packages/libfont-ttf-perl/trunk/lib/Font/TTF/GDEF.pm
packages/libfont-ttf-perl/trunk/lib/Font/TTF/GPOS.pm
packages/libfont-ttf-perl/trunk/lib/Font/TTF/GSUB.pm
packages/libfont-ttf-perl/trunk/lib/Font/TTF/Glyf.pm
packages/libfont-ttf-perl/trunk/lib/Font/TTF/Glyph.pm
packages/libfont-ttf-perl/trunk/lib/Font/TTF/Hdmx.pm
packages/libfont-ttf-perl/trunk/lib/Font/TTF/Head.pm
packages/libfont-ttf-perl/trunk/lib/Font/TTF/Hhea.pm
packages/libfont-ttf-perl/trunk/lib/Font/TTF/Hmtx.pm
packages/libfont-ttf-perl/trunk/lib/Font/TTF/Kern.pm
packages/libfont-ttf-perl/trunk/lib/Font/TTF/Kern/ClassArray.pm
packages/libfont-ttf-perl/trunk/lib/Font/TTF/Kern/CompactClassArray.pm
packages/libfont-ttf-perl/trunk/lib/Font/TTF/Kern/OrderedList.pm
packages/libfont-ttf-perl/trunk/lib/Font/TTF/Kern/StateTable.pm
packages/libfont-ttf-perl/trunk/lib/Font/TTF/Kern/Subtable.pm
packages/libfont-ttf-perl/trunk/lib/Font/TTF/LTSH.pm
packages/libfont-ttf-perl/trunk/lib/Font/TTF/Loca.pm
packages/libfont-ttf-perl/trunk/lib/Font/TTF/Manual.pod
packages/libfont-ttf-perl/trunk/lib/Font/TTF/Maxp.pm
packages/libfont-ttf-perl/trunk/lib/Font/TTF/Mort.pm
packages/libfont-ttf-perl/trunk/lib/Font/TTF/Mort/Chain.pm
packages/libfont-ttf-perl/trunk/lib/Font/TTF/Mort/Contextual.pm
packages/libfont-ttf-perl/trunk/lib/Font/TTF/Mort/Insertion.pm
packages/libfont-ttf-perl/trunk/lib/Font/TTF/Mort/Ligature.pm
packages/libfont-ttf-perl/trunk/lib/Font/TTF/Mort/Noncontextual.pm
packages/libfont-ttf-perl/trunk/lib/Font/TTF/Mort/Rearrangement.pm
packages/libfont-ttf-perl/trunk/lib/Font/TTF/Mort/Subtable.pm
packages/libfont-ttf-perl/trunk/lib/Font/TTF/Name.pm
packages/libfont-ttf-perl/trunk/lib/Font/TTF/OS_2.pm
packages/libfont-ttf-perl/trunk/lib/Font/TTF/OldCmap.pm
packages/libfont-ttf-perl/trunk/lib/Font/TTF/OldMort.pm
packages/libfont-ttf-perl/trunk/lib/Font/TTF/PCLT.pm
packages/libfont-ttf-perl/trunk/lib/Font/TTF/PSNames.pm
packages/libfont-ttf-perl/trunk/lib/Font/TTF/Post.pm
packages/libfont-ttf-perl/trunk/lib/Font/TTF/Prep.pm
packages/libfont-ttf-perl/trunk/lib/Font/TTF/Prop.pm
packages/libfont-ttf-perl/trunk/lib/Font/TTF/Segarr.pm
packages/libfont-ttf-perl/trunk/lib/Font/TTF/Table.pm
packages/libfont-ttf-perl/trunk/lib/Font/TTF/Ttc.pm
packages/libfont-ttf-perl/trunk/lib/Font/TTF/Ttopen.pm
packages/libfont-ttf-perl/trunk/lib/Font/TTF/Useall.pm
packages/libfont-ttf-perl/trunk/lib/Font/TTF/Utils.pm
packages/libfont-ttf-perl/trunk/lib/Font/TTF/Vhea.pm
packages/libfont-ttf-perl/trunk/lib/Font/TTF/Vmtx.pm
packages/libfont-ttf-perl/trunk/lib/Font/TTF/Win32.pm
packages/libfont-ttf-perl/trunk/lib/Font/TTF/XMLparse.pm
packages/libfont-ttf-perl/trunk/lib/ttfmod.pl
Log:
* New upstream release.
Modified: packages/libfont-ttf-perl/trunk/META.yml
===================================================================
--- packages/libfont-ttf-perl/trunk/META.yml 2006-01-17 02:56:43 UTC (rev 1966)
+++ packages/libfont-ttf-perl/trunk/META.yml 2006-01-17 03:07:20 UTC (rev 1967)
@@ -1,7 +1,7 @@
# http://module-build.sourceforge.net/META-spec.html
#XXXXXXX This is a prototype!!! It will change in the future!!! XXXXX#
name: Font-TTF
-version: 0.35
+version: 0.37
version_from: lib/Font/TTF/Font.pm
installdirs: site
requires:
Modified: packages/libfont-ttf-perl/trunk/debian/changelog
===================================================================
--- packages/libfont-ttf-perl/trunk/debian/changelog 2006-01-17 02:56:43 UTC (rev 1966)
+++ packages/libfont-ttf-perl/trunk/debian/changelog 2006-01-17 03:07:20 UTC (rev 1967)
@@ -1,3 +1,9 @@
+libfont-ttf-perl (0.37-1) unstable; urgency=low
+
+ * New upstream release.
+
+ -- Russ Allbery <rra at debian.org> Mon, 16 Jan 2006 19:06:53 -0800
+
libfont-ttf-perl (0.35-1) unstable; urgency=low
* New upstream release
Modified: packages/libfont-ttf-perl/trunk/lib/Font/TTF/AATKern.pm
===================================================================
--- packages/libfont-ttf-perl/trunk/lib/Font/TTF/AATKern.pm 2006-01-17 02:56:43 UTC (rev 1966)
+++ packages/libfont-ttf-perl/trunk/lib/Font/TTF/AATKern.pm 2006-01-17 03:07:20 UTC (rev 1967)
@@ -1,140 +1,140 @@
-package Font::TTF::AATKern;
-
-=head1 NAME
-
-Font::TTF::AATKern
-
-=head1 METHODS
-
-=cut
-
-use strict;
-use vars qw(@ISA);
-use Font::TTF::Utils;
-use Font::TTF::AATutils;
-use Font::TTF::Kern::Subtable;
-
- at ISA = qw(Font::TTF::Table);
-
-=head2 $t->read
-
-Reads the table into memory
-
-=cut
-
-sub read
-{
- my ($self) = @_;
-
- $self->SUPER::read or return $self;
-
- my ($dat, $fh, $numSubtables);
- $fh = $self->{' INFILE'};
-
- $fh->read($dat, 8);
- ($self->{'version'}, $numSubtables) = TTF_Unpack("fL", $dat);
-
- my $subtables = [];
- foreach (1 .. $numSubtables) {
- my $subtableStart = $fh->tell();
-
- $fh->read($dat, 8);
- my ($length, $coverage, $tupleIndex) = TTF_Unpack("LSS", $dat);
- my $type = $coverage & 0x00ff;
-
- my $subtable = Font::TTF::Kern::Subtable->create($type, $coverage, $length);
- $subtable->read($fh);
-
- $subtable->{'tupleIndex'} = $tupleIndex if $subtable->{'variation'};
- $subtable->{' PARENT'} = $self;
- push @$subtables, $subtable;
- }
-
- $self->{'subtables'} = $subtables;
-
- $self;
-}
-
-=head2 $t->out($fh)
-
-Writes the table to a file either from memory or by copying
-
-=cut
-
-sub out
-{
- my ($self, $fh) = @_;
-
- return $self->SUPER::out($fh) unless $self->{' read'};
-
- my $subtables = $self->{'subtables'};
- $fh->print(TTF_Pack("fL", $self->{'version'}, scalar @$subtables));
-
- foreach (@$subtables) {
- $_->out($fh);
- }
-}
-
-=head2 $t->print($fh)
-
-Prints a human-readable representation of the table
-
-=cut
-
-sub print
-{
- my ($self, $fh) = @_;
-
- $self->read unless $self->{' read'};
-
- $fh = 'STDOUT' unless defined $fh;
-
- $fh->printf("version %f\n", $self->{'version'});
-
- my $subtables = $self->{'subtables'};
- foreach (@$subtables) {
- $_->print($fh);
- }
-}
-
-sub dumpXML
-{
- my ($self, $fh) = @_;
- $self->read unless $self->{' read'};
-
- my $post = $self->{' PARENT'}->{'post'};
- $post->read;
-
- $fh = 'STDOUT' unless defined $fh;
- $fh->printf("<kern version=\"%f\">\n", $self->{'version'});
-
- my $subtables = $self->{'subtables'};
- foreach (@$subtables) {
- $fh->printf("<%s", $_->type);
- $fh->printf(" vertical=\"1\"") if $_->{'vertical'};
- $fh->printf(" crossStream=\"1\"") if $_->{'crossStream'};
- $fh->printf(" variation=\"1\"") if $_->{'variation'};
- $fh->printf(" tupleIndex=\"%s\"", $_->{'tupleIndex'}) if exists $_->{'tupleIndex'};
- $fh->printf(">\n");
-
- $_->dumpXML($fh);
-
- $fh->printf("</%s>\n", $_->type);
- }
-
- $fh->printf("</kern>\n");
-}
-
-1;
-
-=head1 BUGS
-
-None known
-
-=head1 AUTHOR
-
-Jonathan Kew L<Jonathan_Kew at sil.org>. See L<Font::TTF::Font> for copyright and
-licensing.
-
-=cut
-
+package Font::TTF::AATKern;
+
+=head1 NAME
+
+Font::TTF::AATKern
+
+=head1 METHODS
+
+=cut
+
+use strict;
+use vars qw(@ISA);
+use Font::TTF::Utils;
+use Font::TTF::AATutils;
+use Font::TTF::Kern::Subtable;
+
+ at ISA = qw(Font::TTF::Table);
+
+=head2 $t->read
+
+Reads the table into memory
+
+=cut
+
+sub read
+{
+ my ($self) = @_;
+
+ $self->SUPER::read or return $self;
+
+ my ($dat, $fh, $numSubtables);
+ $fh = $self->{' INFILE'};
+
+ $fh->read($dat, 8);
+ ($self->{'version'}, $numSubtables) = TTF_Unpack("fL", $dat);
+
+ my $subtables = [];
+ foreach (1 .. $numSubtables) {
+ my $subtableStart = $fh->tell();
+
+ $fh->read($dat, 8);
+ my ($length, $coverage, $tupleIndex) = TTF_Unpack("LSS", $dat);
+ my $type = $coverage & 0x00ff;
+
+ my $subtable = Font::TTF::Kern::Subtable->create($type, $coverage, $length);
+ $subtable->read($fh);
+
+ $subtable->{'tupleIndex'} = $tupleIndex if $subtable->{'variation'};
+ $subtable->{' PARENT'} = $self;
+ push @$subtables, $subtable;
+ }
+
+ $self->{'subtables'} = $subtables;
+
+ $self;
+}
+
+=head2 $t->out($fh)
+
+Writes the table to a file either from memory or by copying
+
+=cut
+
+sub out
+{
+ my ($self, $fh) = @_;
+
+ return $self->SUPER::out($fh) unless $self->{' read'};
+
+ my $subtables = $self->{'subtables'};
+ $fh->print(TTF_Pack("fL", $self->{'version'}, scalar @$subtables));
+
+ foreach (@$subtables) {
+ $_->out($fh);
+ }
+}
+
+=head2 $t->print($fh)
+
+Prints a human-readable representation of the table
+
+=cut
+
+sub print
+{
+ my ($self, $fh) = @_;
+
+ $self->read unless $self->{' read'};
+
+ $fh = 'STDOUT' unless defined $fh;
+
+ $fh->printf("version %f\n", $self->{'version'});
+
+ my $subtables = $self->{'subtables'};
+ foreach (@$subtables) {
+ $_->print($fh);
+ }
+}
+
+sub dumpXML
+{
+ my ($self, $fh) = @_;
+ $self->read unless $self->{' read'};
+
+ my $post = $self->{' PARENT'}->{'post'};
+ $post->read;
+
+ $fh = 'STDOUT' unless defined $fh;
+ $fh->printf("<kern version=\"%f\">\n", $self->{'version'});
+
+ my $subtables = $self->{'subtables'};
+ foreach (@$subtables) {
+ $fh->printf("<%s", $_->type);
+ $fh->printf(" vertical=\"1\"") if $_->{'vertical'};
+ $fh->printf(" crossStream=\"1\"") if $_->{'crossStream'};
+ $fh->printf(" variation=\"1\"") if $_->{'variation'};
+ $fh->printf(" tupleIndex=\"%s\"", $_->{'tupleIndex'}) if exists $_->{'tupleIndex'};
+ $fh->printf(">\n");
+
+ $_->dumpXML($fh);
+
+ $fh->printf("</%s>\n", $_->type);
+ }
+
+ $fh->printf("</kern>\n");
+}
+
+1;
+
+=head1 BUGS
+
+None known
+
+=head1 AUTHOR
+
+Jonathan Kew L<Jonathan_Kew at sil.org>. See L<Font::TTF::Font> for copyright and
+licensing.
+
+=cut
+
Modified: packages/libfont-ttf-perl/trunk/lib/Font/TTF/AATutils.pm
===================================================================
--- packages/libfont-ttf-perl/trunk/lib/Font/TTF/AATutils.pm 2006-01-17 02:56:43 UTC (rev 1966)
+++ packages/libfont-ttf-perl/trunk/lib/Font/TTF/AATutils.pm 2006-01-17 03:07:20 UTC (rev 1967)
@@ -1,688 +1,689 @@
-package Font::TTF::AATutils;
-
-use strict;
-use vars qw(@ISA @EXPORT);
-require Exporter;
-
-use Font::TTF::Utils;
-
- at ISA = qw(Exporter);
- at EXPORT = qw(
- AAT_read_lookup
- AAT_pack_lookup
- AAT_write_lookup
- AAT_pack_classes
- AAT_write_classes
- AAT_pack_states
- AAT_write_states
- AAT_read_state_table
- AAT_read_subtable
- xmldump
-);
-
-sub xmldump
-{
- my ($var, $links, $depth, $processedVars, $type) = @_;
-
- $processedVars = {} unless (defined $processedVars);
- print("<?xml version='1.0' encoding='UTF-8'?>\n") if $depth == 0; # not necessarily true encoding for all text!
-
- my $indent = "\t" x $depth;
-
- my ($objType, $addr) = ($var =~ m/^.+=(.+)\((.+)\)$/);
- unless (defined $type) {
- if (defined $addr) {
- if (defined $processedVars->{$addr}) {
- if ($links) {
- printf("%s%s\n", $indent, "<a href=\"#$addr\">$objType</a>");
- }
- else {
- printf("%s%s\n", $indent, "<a>$objType</a>");
- }
- return;
- }
- $processedVars->{$addr} = 1;
- }
- }
-
- $type = ref $var unless defined $type;
-
- if ($type eq 'REF') {
- printf("%s<ref val=\"%s\"/>\n", $indent, $$var);
- }
- elsif ($type eq 'SCALAR') {
- printf("%s<scalar>%s</scalar>\n", $indent, $var);
- }
- elsif ($type eq 'ARRAY') {
- # printf("%s<array>\n", $indent);
- foreach (0 .. $#$var) {
- if (ref($var->[$_])) {
- printf("%s<arrayItem index=\"%d\">\n", $indent, $_);
- xmldump($var->[$_], $links, $depth + 1, $processedVars);
- printf("%s</arrayItem>\n", $indent);
- }
- else {
- printf("%s<arrayItem index=\"%d\">%s</arrayItem>\n", $indent, $_, $var->[$_]);
- }
- }
- # printf("%s</array>\n", $indent);
- }
- elsif ($type eq 'HASH') {
- # printf("%s<hash>\n", $indent);
- foreach (sort keys %$var) {
- if (ref($var->{$_})) {
- printf("%s<hashElem key=\"%s\">\n", $indent, $_);
- xmldump($var->{$_}, $links, $depth + 1, $processedVars);
- printf("%s</hashElem>\n", $indent);
- }
- else {
- printf("%s<hashElem key=\"%s\">%s</hashElem>\n", $indent, $_, $var->{$_});
- }
- }
- # printf("%s</hash>\n", $indent);
- }
- elsif ($type eq 'CODE') {
- printf("%s<CODE/>\n", $indent, $var);
- }
- elsif ($type eq 'GLOB') {
- printf("%s<GLOB/>\n", $indent, $var);
- }
- elsif ($type eq '') {
- printf("%s<val>%s</val>\n", $indent, $var);
- }
- else {
- if ($links) {
- printf("%s<obj class=\"%s\" id=\"#%s\">\n", $indent, $type, $addr);
- }
- else {
- printf("%s<obj class=\"%s\">\n", $indent, $type);
- }
- xmldump($var, $links, $depth + 1, $processedVars, $objType);
- printf("%s</obj>\n", $indent);
- }
-}
-
-=head2 ($classes, $states) = AAT_read_subtable($fh, $baseOffset, $subtableStart, $limits)
-
-=cut
-
-sub AAT_read_subtable
-{
- my ($fh, $baseOffset, $subtableStart, $limits) = @_;
-
- my $limit = 0xffffffff;
- foreach (@$limits) {
- $limit = $_ if ($_ > $subtableStart and $_ < $limit);
- }
- die if $limit == 0xffffffff;
-
- my $dat;
- $fh->seek($baseOffset + $subtableStart, IO::File::SEEK_SET);
- $fh->read($dat, $limit - $subtableStart);
-
- $dat;
-}
-
-=head2 $length = AAT_write_state_table($fh, $classes, $states, $numExtraTables, $packEntry)
-
-$packEntry is a subroutine for packing an entry into binary form, called as
-
-$dat = $packEntry($entry, $entryTable, $numEntries)
-
-where the entry is a comma-separated list of nextStateOffset, flags, actions
-
-=cut
-
-sub AAT_pack_state_table
-{
- my ($classes, $states, $numExtraTables, $packEntry) = @_;
-
- my ($dat) = pack("n*", (0) x (4 + $numExtraTables)); # placeholders for stateSize, classTable, stateArray, entryTable
-
- my ($firstGlyph, $lastGlyph) = (0xffff, 0, 0);
- my (@classTable, $i);
- foreach $i (0 .. $#$classes) {
- my $class = $classes->[$i];
- foreach (@$class) {
- $firstGlyph = $_ if $_ < $firstGlyph;
- $lastGlyph = $_ if $_ > $lastGlyph;
- $classTable[$_] = $i;
- }
- }
-
- my $classTable = length($dat);
- $dat .= pack("nnC*", $firstGlyph, $lastGlyph - $firstGlyph + 1,
- map { defined $classTable[$_] ? $classTable[$_] : 1 } ($firstGlyph .. $lastGlyph));
- $dat .= pack("C", 0) if (($lastGlyph - $firstGlyph) & 1) == 0; # pad if odd number of glyphs
-
- my $stateArray = length($dat);
- my (@entries, %entries);
- my $state = $states->[0];
- my $stateSize = @$state;
- die "stateSize below minimum allowed (4)" if $stateSize < 4;
- die "stateSize (" . $stateSize . ") too small for max class number (" . $#$classes . ")" if $stateSize < $#$classes + 1;
- warn "state array has unreachable columns" if $stateSize > $#$classes + 1;
-
- foreach (@$states) {
- die "inconsistent state size" if @$_ != $stateSize;
- foreach (@$_) {
- my $actions = $_->{'actions'};
- my $entry = join(",", $stateArray + $_->{'nextState'} * $stateSize, $_->{'flags'}, ref($actions) eq 'ARRAY' ? @$actions : $actions);
- if (not defined $entries{$entry}) {
- push @entries, $entry;
- $entries{$entry} = $#entries;
- die "too many different state array entries" if $#entries == 256;
- }
- $dat .= pack("C", $entries{$entry});
- }
- }
- $dat .= pack("C", 0) if (@$states & 1) != 0 and ($stateSize & 1) != 0; # pad if state array size is odd
-
- my $entryTable = length($dat);
- $dat .= map { &$packEntry($_, $entryTable, $#entries + 1) } @entries;
-
- my ($dat1) = pack("nnnn", $stateSize, $classTable, $stateArray, $entryTable);
- substr($dat, 0, length($dat1)) = $dat1;
-
- return $dat;
-}
-
-sub AAT_write_state_table
-{
- my ($fh, $classes, $states, $numExtraTables, $packEntry) = @_;
-
- my $stateTableStart = $fh->tell();
-
- $fh->print(pack("n*", (0) x (4 + $numExtraTables))); # placeholders for stateSize, classTable, stateArray, entryTable
-
- my ($firstGlyph, $lastGlyph) = (0xffff, 0, 0);
- my (@classTable, $i);
- foreach $i (0 .. $#$classes) {
- my $class = $classes->[$i];
- foreach (@$class) {
- $firstGlyph = $_ if $_ < $firstGlyph;
- $lastGlyph = $_ if $_ > $lastGlyph;
- $classTable[$_] = $i;
- }
- }
-
- my $classTable = $fh->tell() - $stateTableStart;
- $fh->print(pack("nnC*", $firstGlyph, $lastGlyph - $firstGlyph + 1,
- map { defined $classTable[$_] ? $classTable[$_] : 1 } ($firstGlyph .. $lastGlyph)));
- $fh->print(pack("C", 0)) if (($lastGlyph - $firstGlyph) & 1) == 0; # pad if odd number of glyphs
-
- my $stateArray = $fh->tell() - $stateTableStart;
- my (@entries, %entries);
- my $state = $states->[0];
- my $stateSize = @$state;
- die "stateSize below minimum allowed (4)" if $stateSize < 4;
- die "stateSize (" . $stateSize . ") too small for max class number (" . $#$classes . ")" if $stateSize < $#$classes + 1;
- warn "state array has unreachable columns" if $stateSize > $#$classes + 1;
-
- foreach (@$states) {
- die "inconsistent state size" if @$_ != $stateSize;
- foreach (@$_) {
- my $actions = $_->{'actions'};
- my $entry = join(",", $stateArray + $_->{'nextState'} * $stateSize, $_->{'flags'}, ref($actions) eq 'ARRAY' ? @$actions : $actions);
- if (not defined $entries{$entry}) {
- push @entries, $entry;
- $entries{$entry} = $#entries;
- die "too many different state array entries" if $#entries == 256;
- }
- $fh->print(pack("C", $entries{$entry}));
- }
- }
- $fh->print(pack("C", 0)) if (@$states & 1) != 0 and ($stateSize & 1) != 0; # pad if state array size is odd
-
- my $entryTable = $fh->tell() - $stateTableStart;
- $fh->print(map { &$packEntry($_, $entryTable, $#entries + 1) } @entries);
-
- my $length = $fh->tell() - $stateTableStart;
- $fh->seek($stateTableStart, IO::File::SEEK_SET);
- $fh->print(pack("nnnn", $stateSize, $classTable, $stateArray, $entryTable));
-
- $fh->seek($stateTableStart + $length, IO::File::SEEK_SET);
- $length;
-}
-
-sub AAT_pack_classes
-{
- my ($classes) = @_;
-
- my ($firstGlyph, $lastGlyph) = (0xffff, 0, 0);
- my (@classTable, $i);
- foreach $i (0 .. $#$classes) {
- my $class = $classes->[$i];
- foreach (@$class) {
- $firstGlyph = $_ if $_ < $firstGlyph;
- $lastGlyph = $_ if $_ > $lastGlyph;
- $classTable[$_] = $i;
- }
- }
-
- my ($dat) = pack("nnC*", $firstGlyph, $lastGlyph - $firstGlyph + 1,
- map { defined $classTable[$_] ? $classTable[$_] : 1 } ($firstGlyph .. $lastGlyph));
- $dat .= pack("C", 0) if (($lastGlyph - $firstGlyph) & 1) == 0; # pad if odd number of glyphs
-
- return $dat;
-}
-
-sub AAT_write_classes
-{
- my ($fh, $classes) = @_;
-
- $fh->print(AAT_pack_classes($fh, $classes));
-}
-
-sub AAT_pack_states
-{
- my ($classes, $stateArray, $states, $buildEntryProc) = @_;
-
- my ($entries, %entryHash);
- my $state = $states->[0];
- my $stateSize = @$state;
-
- die "stateSize below minimum allowed (4)" if $stateSize < 4;
- die "stateSize (" . $stateSize . ") too small for max class number (" . $#$classes . ")" if $stateSize < $#$classes + 1;
- warn "state array has unreachable columns" if $stateSize > $#$classes + 1;
-
- my ($dat);
- foreach (@$states) {
- die "inconsistent state size" if @$_ != $stateSize;
- foreach (@$_) {
- my $entry = join(",", $stateArray + $_->{'nextState'} * $stateSize, &$buildEntryProc($_));
- if (not defined $entryHash{$entry}) {
- push @$entries, $entry;
- $entryHash{$entry} = $#$entries;
- die "too many different state array entries" if $#$entries == 256;
- }
- $dat .= pack("C", $entryHash{$entry});
- }
- }
- $dat .= pack("C", 0) if (@$states & 1) != 0 and ($stateSize & 1) != 0; # pad if state array size is odd
-
- ($dat, $stateSize, $entries);
-}
-
-sub AAT_write_states
-{
- my ($fh, $classes, $stateArray, $states, $buildEntryProc) = @_;
-
- my ($entries, %entryHash);
- my $state = $states->[0];
- my $stateSize = @$state;
-
- die "stateSize below minimum allowed (4)" if $stateSize < 4;
- die "stateSize (" . $stateSize . ") too small for max class number (" . $#$classes . ")" if $stateSize < $#$classes + 1;
- warn "state array has unreachable columns" if $stateSize > $#$classes + 1;
-
- foreach (@$states) {
- die "inconsistent state size" if @$_ != $stateSize;
- foreach (@$_) {
- my $entry = join(",", $stateArray + $_->{'nextState'} * $stateSize, &$buildEntryProc($_));
- if (not defined $entryHash{$entry}) {
- push @$entries, $entry;
- $entryHash{$entry} = $#$entries;
- die "too many different state array entries" if $#$entries == 256;
- }
- $fh->print(pack("C", $entryHash{$entry}));
- }
- }
- $fh->print(pack("C", 0)) if (@$states & 1) != 0 and ($stateSize & 1) != 0; # pad if state array size is odd
-
- ($stateSize, $entries);
-}
-
-=head2 ($classes, $states, $entries) = AAT_read_state_table($fh, $numActionWords)
-
-=cut
-
-sub AAT_read_state_table
-{
- my ($fh, $numActionWords) = @_;
-
- my $stateTableStart = $fh->tell();
- my $dat;
- $fh->read($dat, 8);
- my ($stateSize, $classTable, $stateArray, $entryTable) = unpack("nnnn", $dat);
-
- my $classes; # array of lists of glyphs
-
- $fh->seek($stateTableStart + $classTable, IO::File::SEEK_SET);
- $fh->read($dat, 4);
- my ($firstGlyph, $nGlyphs) = unpack("nn", $dat);
- $fh->read($dat, $nGlyphs);
- foreach (unpack("C*", $dat)) {
- if ($_ != 1) {
- my $class = $classes->[$_];
- push(@$class, $firstGlyph);
- $classes->[$_] = $class unless defined $classes->[$_];
- }
- $firstGlyph++;
- }
-
- $fh->seek($stateTableStart + $stateArray, IO::File::SEEK_SET);
- my $states; # array of arrays of hashes{nextState, flags, actions}
-
- my $entrySize = 4 + ($numActionWords * 2);
- my $lastState = 1;
- my $entries;
- while ($#$states < $lastState) {
- $fh->read($dat, $stateSize);
- my @stateEntries = unpack("C*", $dat);
- my $state;
- foreach (@stateEntries) {
- if (not defined $entries->[$_]) {
- my $loc = $fh->tell();
- $fh->seek($stateTableStart + $entryTable + ($_ * $entrySize), IO::File::SEEK_SET);
- $fh->read($dat, $entrySize);
- my ($nextState, $flags, $actions);
- ($nextState, $flags, @$actions) = unpack("n*", $dat);
- $nextState -= $stateArray;
- $nextState /= $stateSize;
- $entries->[$_] = { 'nextState' => $nextState, 'flags' => $flags };
- $entries->[$_]->{'actions'} = $actions if $numActionWords > 0;
- $lastState = $nextState if ($nextState > $lastState);
- $fh->seek($loc, IO::File::SEEK_SET);
- }
- push(@$state, $entries->[$_]);
- }
- push(@$states, $state);
- }
-
- ($classes, $states, $entries);
-}
-
-=head2 ($format, $lookup) = AAT_read_lookup($fh, $valueSize, $length, $default)
-
-=cut
-
-sub AAT_read_lookup
-{
- my ($fh, $valueSize, $length, $default) = @_;
-
- my $lookupStart = $fh->tell();
- my ($dat, $unpackChar);
- if ($valueSize == 1) {
- $unpackChar = "C";
- }
- elsif ($valueSize == 2) {
- $unpackChar = "n";
- }
- elsif ($valueSize == 4) {
- $unpackChar = "N";
- }
- else {
- die "unsupported value size";
- }
-
- $fh->read($dat, 2);
- my $format = unpack("n", $dat);
- my $lookup;
-
- if ($format == 0) {
- $fh->read($dat, $length - 2);
- my $i = -1;
- $lookup = { map { $i++; ($_ != $default) ? ($i, $_) : () } unpack($unpackChar . "*", $dat) };
- }
-
- elsif ($format == 2) {
- $fh->read($dat, 10);
- my ($unitSize, $nUnits, $searchRange, $entrySelector, $rangeShift) = unpack("nnnnn", $dat);
- die if $unitSize != 4 + $valueSize;
- foreach (1 .. $nUnits) {
- $fh->read($dat, $unitSize);
- my ($lastGlyph, $firstGlyph, $value) = unpack("nn" . $unpackChar, $dat);
- if ($firstGlyph != 0xffff and $value != $default) {
- foreach ($firstGlyph .. $lastGlyph) {
- $lookup->{$_} = $value;
- }
- }
- }
- }
-
- elsif ($format == 4) {
- $fh->read($dat, 10);
- my ($unitSize, $nUnits, $searchRange, $entrySelector, $rangeShift) = unpack("nnnnn", $dat);
- die if $unitSize != 6;
- foreach (1 .. $nUnits) {
- $fh->read($dat, $unitSize);
- my ($lastGlyph, $firstGlyph, $offset) = unpack("nnn", $dat);
- if ($firstGlyph != 0xffff) {
- my $loc = $fh->tell();
- $fh->seek($lookupStart + $offset, IO::File::SEEK_SET);
- $fh->read($dat, ($lastGlyph - $firstGlyph + 1) * $valueSize);
- my @values = unpack($unpackChar . "*", $dat);
- foreach (0 .. $lastGlyph - $firstGlyph) {
- $lookup->{$firstGlyph + $_} = $values[$_] if $values[$_] != $default;
- }
- $fh->seek($loc, IO::File::SEEK_SET);
- }
- }
- }
-
- elsif ($format == 6) {
- $fh->read($dat, 10);
- my ($unitSize, $nUnits, $searchRange, $entrySelector, $rangeShift) = unpack("nnnnn", $dat);
- die if $unitSize != 2 + $valueSize;
- foreach (1 .. $nUnits) {
- $fh->read($dat, $unitSize);
- my ($glyph, $value) = unpack("n" . $unpackChar, $dat);
- $lookup->{$glyph} = $value if $glyph != 0xffff and $value != $default;
- }
- }
-
- elsif ($format == 8) {
- $fh->read($dat, 4);
- my ($firstGlyph, $glyphCount) = unpack("nn", $dat);
- $fh->read($dat, $glyphCount * $valueSize);
- $firstGlyph--;
- $lookup = { map { $firstGlyph++; $_ != $default ? ($firstGlyph, $_) : () } unpack($unpackChar . "*", $dat) };
- }
-
- else {
- die "unknown lookup format";
- }
-
- $fh->seek($lookupStart + $length, IO::File::SEEK_SET);
-
- ($format, $lookup);
-}
-
-=head2 AAT_write_lookup($fh, $format, $lookup, $valueSize, $default)
-
-=cut
-
-sub AAT_pack_lookup
-{
- my ($format, $lookup, $valueSize, $default) = @_;
-
- my $packChar;
- if ($valueSize == 1) {
- $packChar = "C";
- }
- elsif ($valueSize == 2) {
- $packChar = "n";
- }
- elsif ($valueSize == 4) {
- $packChar = "N";
- }
- else {
- die "unsupported value size";
- }
-
- my ($dat) = pack("n", $format);
-
- my ($firstGlyph, $lastGlyph) = (0xffff, 0);
- foreach (keys %$lookup) {
- $firstGlyph = $_ if $_ < $firstGlyph;
- $lastGlyph = $_ if $_ > $lastGlyph;
- }
- my $glyphCount = $lastGlyph - $firstGlyph + 1;
-
- if ($format == 0) {
- $dat .= pack($packChar . "*", map { defined $lookup->{$_} ? $lookup->{$_} : defined $default ? $default : $_ } (0 .. $lastGlyph));
- }
-
- elsif ($format == 2) {
- my $prev = $default;
- my $segStart = $firstGlyph;
- my $dat1;
- foreach ($firstGlyph .. $lastGlyph + 1) {
- my $val = $lookup->{$_};
- $val = $default unless defined $val;
- if ($val != $prev) {
- $dat1 .= pack("nn" . $packChar, $_ - 1, $segStart, $prev) if $prev != $default;
- $prev = $val;
- $segStart = $_;
- }
- }
- $dat1 .= pack("nn" . $packChar, 0xffff, 0xffff, 0);
- my $unitSize = 4 + $valueSize;
- $dat .= pack("nnnnn", $unitSize, TTF_bininfo(length($dat1) / $unitSize, $unitSize));
- $dat .= $dat1;
- }
-
- elsif ($format == 4) {
- my $segArray = new Font::TTF::Segarr($valueSize);
- $segArray->add_segment($firstGlyph, 1, map { $lookup->{$_} } ($firstGlyph .. $lastGlyph));
- my ($start, $end, $offset);
- $offset = 12 + @$segArray * 6 + 6; # 12 is size of format word + binSearchHeader; 6 bytes per segment; 6 for terminating segment
- my $dat1;
- foreach (@$segArray) {
- $start = $_->{'START'};
- $end = $start + $_->{'LEN'} - 1;
- $dat1 .= pack("nnn", $end, $start, $offset);
- $offset += $_->{'LEN'} * 2;
- }
- $dat1 .= pack("nnn", 0xffff, 0xffff, 0);
- $dat .= pack("nnnnn", 6, TTF_bininfo(length($dat1) / 6, 6));
- $dat .= $dat1;
- foreach (@$segArray) {
- $dat1 = $_->{'VAL'};
- $dat .= pack($packChar . "*", @$dat1);
- }
- }
-
- elsif ($format == 6) {
- die "unsupported" if $valueSize != 2;
- my $dat1 = pack("n*", map { $_, $lookup->{$_} } sort { $a <=> $b } grep { $lookup->{$_} ne $default } keys %$lookup);
- my $unitSize = 2 + $valueSize;
- $dat .= pack("nnnnn", $unitSize, TTF_bininfo(length($dat1) / $unitSize, $unitSize));
- $dat .= $dat1;
- }
-
- elsif ($format == 8) {
- $dat .= pack("nn", $firstGlyph, $lastGlyph - $firstGlyph + 1);
- $dat .= pack($packChar . "*", map { defined $lookup->{$_} ? $lookup->{$_} : defined $default ? $default : $_ } ($firstGlyph .. $lastGlyph));
- }
-
- else {
- die "unknown lookup format";
- }
-
- my $padBytes = (4 - (length($dat) & 3)) & 3;
- $dat .= pack("C*", (0) x $padBytes);
-
- return $dat;
-}
-
-sub AAT_write_lookup
-{
- my ($fh, $format, $lookup, $valueSize, $default) = @_;
-
- my $lookupStart = $fh->tell();
- my $packChar;
- if ($valueSize == 1) {
- $packChar = "C";
- }
- elsif ($valueSize == 2) {
- $packChar = "n";
- }
- elsif ($valueSize == 4) {
- $packChar = "N";
- }
- else {
- die "unsupported value size";
- }
-
- $fh->print(pack("n", $format));
-
- my ($firstGlyph, $lastGlyph) = (0xffff, 0);
- foreach (keys %$lookup) {
- $firstGlyph = $_ if $_ < $firstGlyph;
- $lastGlyph = $_ if $_ > $lastGlyph;
- }
- my $glyphCount = $lastGlyph - $firstGlyph + 1;
-
- if ($format == 0) {
- $fh->print(pack($packChar . "*", map { defined $lookup->{$_} ? $lookup->{$_} : defined $default ? $default : $_ } (0 .. $lastGlyph)));
- }
-
- elsif ($format == 2) {
- my $prev = $default;
- my $segStart = $firstGlyph;
- my $dat;
- foreach ($firstGlyph .. $lastGlyph + 1) {
- my $val = $lookup->{$_};
- $val = $default unless defined $val;
- if ($val != $prev) {
- $dat .= pack("nn" . $packChar, $_ - 1, $segStart, $prev) if $prev != $default;
- $prev = $val;
- $segStart = $_;
- }
- }
- $dat .= pack("nn" . $packChar, 0xffff, 0xffff, 0);
- my $unitSize = 4 + $valueSize;
- $fh->print(pack("nnnnn", $unitSize, TTF_bininfo(length($dat) / $unitSize, $unitSize)));
- $fh->print($dat);
- }
-
- elsif ($format == 4) {
- my $segArray = new Font::TTF::Segarr($valueSize);
- $segArray->add_segment($firstGlyph, 1, map { $lookup->{$_} } ($firstGlyph .. $lastGlyph));
- my ($start, $end, $offset);
- $offset = 12 + @$segArray * 6 + 6; # 12 is size of format word + binSearchHeader; 6 bytes per segment; 6 for terminating segment
- my $dat;
- foreach (@$segArray) {
- $start = $_->{'START'};
- $end = $start + $_->{'LEN'} - 1;
- $dat .= pack("nnn", $end, $start, $offset);
- $offset += $_->{'LEN'} * 2;
- }
- $dat .= pack("nnn", 0xffff, 0xffff, 0);
- $fh->print(pack("nnnnn", 6, TTF_bininfo(length($dat) / 6, 6)));
- $fh->print($dat);
- foreach (@$segArray) {
- $dat = $_->{'VAL'};
- $fh->print(pack($packChar . "*", @$dat));
- }
- }
-
- elsif ($format == 6) {
- die "unsupported" if $valueSize != 2;
- my $dat = pack("n*", map { $_, $lookup->{$_} } sort { $a <=> $b } grep { $lookup->{$_} ne $default } keys %$lookup);
- my $unitSize = 2 + $valueSize;
- $fh->print(pack("nnnnn", $unitSize, TTF_bininfo(length($dat) / $unitSize, $unitSize)));
- $fh->print($dat);
- }
-
- elsif ($format == 8) {
- $fh->print(pack("nn", $firstGlyph, $lastGlyph - $firstGlyph + 1));
- $fh->print(pack($packChar . "*", map { defined $lookup->{$_} ? $lookup->{$_} : defined $default ? $default : $_ } ($firstGlyph .. $lastGlyph)));
- }
-
- else {
- die "unknown lookup format";
- }
-
- my $length = $fh->tell() - $lookupStart;
- my $padBytes = (4 - ($length & 3)) & 3;
- $fh->print(pack("C*", (0) x $padBytes));
- $length += $padBytes;
-
- $length;
-}
-
-1;
-
+package Font::TTF::AATutils;
+
+use strict;
+use vars qw(@ISA @EXPORT);
+require Exporter;
+
+use Font::TTF::Utils;
+use IO::File;
+
+ at ISA = qw(Exporter);
+ at EXPORT = qw(
+ AAT_read_lookup
+ AAT_pack_lookup
+ AAT_write_lookup
+ AAT_pack_classes
+ AAT_write_classes
+ AAT_pack_states
+ AAT_write_states
+ AAT_read_state_table
+ AAT_read_subtable
+ xmldump
+);
+
+sub xmldump
+{
+ my ($var, $links, $depth, $processedVars, $type) = @_;
+
+ $processedVars = {} unless (defined $processedVars);
+ print("<?xml version='1.0' encoding='UTF-8'?>\n") if $depth == 0; # not necessarily true encoding for all text!
+
+ my $indent = "\t" x $depth;
+
+ my ($objType, $addr) = ($var =~ m/^.+=(.+)\((.+)\)$/);
+ unless (defined $type) {
+ if (defined $addr) {
+ if (defined $processedVars->{$addr}) {
+ if ($links) {
+ printf("%s%s\n", $indent, "<a href=\"#$addr\">$objType</a>");
+ }
+ else {
+ printf("%s%s\n", $indent, "<a>$objType</a>");
+ }
+ return;
+ }
+ $processedVars->{$addr} = 1;
+ }
+ }
+
+ $type = ref $var unless defined $type;
+
+ if ($type eq 'REF') {
+ printf("%s<ref val=\"%s\"/>\n", $indent, $$var);
+ }
+ elsif ($type eq 'SCALAR') {
+ printf("%s<scalar>%s</scalar>\n", $indent, $var);
+ }
+ elsif ($type eq 'ARRAY') {
+ # printf("%s<array>\n", $indent);
+ foreach (0 .. $#$var) {
+ if (ref($var->[$_])) {
+ printf("%s<arrayItem index=\"%d\">\n", $indent, $_);
+ xmldump($var->[$_], $links, $depth + 1, $processedVars);
+ printf("%s</arrayItem>\n", $indent);
+ }
+ else {
+ printf("%s<arrayItem index=\"%d\">%s</arrayItem>\n", $indent, $_, $var->[$_]);
+ }
+ }
+ # printf("%s</array>\n", $indent);
+ }
+ elsif ($type eq 'HASH') {
+ # printf("%s<hash>\n", $indent);
+ foreach (sort keys %$var) {
+ if (ref($var->{$_})) {
+ printf("%s<hashElem key=\"%s\">\n", $indent, $_);
+ xmldump($var->{$_}, $links, $depth + 1, $processedVars);
+ printf("%s</hashElem>\n", $indent);
+ }
+ else {
+ printf("%s<hashElem key=\"%s\">%s</hashElem>\n", $indent, $_, $var->{$_});
+ }
+ }
+ # printf("%s</hash>\n", $indent);
+ }
+ elsif ($type eq 'CODE') {
+ printf("%s<CODE/>\n", $indent, $var);
+ }
+ elsif ($type eq 'GLOB') {
+ printf("%s<GLOB/>\n", $indent, $var);
+ }
+ elsif ($type eq '') {
+ printf("%s<val>%s</val>\n", $indent, $var);
+ }
+ else {
+ if ($links) {
+ printf("%s<obj class=\"%s\" id=\"#%s\">\n", $indent, $type, $addr);
+ }
+ else {
+ printf("%s<obj class=\"%s\">\n", $indent, $type);
+ }
+ xmldump($var, $links, $depth + 1, $processedVars, $objType);
+ printf("%s</obj>\n", $indent);
+ }
+}
+
+=head2 ($classes, $states) = AAT_read_subtable($fh, $baseOffset, $subtableStart, $limits)
+
+=cut
+
+sub AAT_read_subtable
+{
+ my ($fh, $baseOffset, $subtableStart, $limits) = @_;
+
+ my $limit = 0xffffffff;
+ foreach (@$limits) {
+ $limit = $_ if ($_ > $subtableStart and $_ < $limit);
+ }
+ die if $limit == 0xffffffff;
+
+ my $dat;
+ $fh->seek($baseOffset + $subtableStart, IO::File::SEEK_SET);
+ $fh->read($dat, $limit - $subtableStart);
+
+ $dat;
+}
+
+=head2 $length = AAT_write_state_table($fh, $classes, $states, $numExtraTables, $packEntry)
+
+$packEntry is a subroutine for packing an entry into binary form, called as
+
+$dat = $packEntry($entry, $entryTable, $numEntries)
+
+where the entry is a comma-separated list of nextStateOffset, flags, actions
+
+=cut
+
+sub AAT_pack_state_table
+{
+ my ($classes, $states, $numExtraTables, $packEntry) = @_;
+
+ my ($dat) = pack("n*", (0) x (4 + $numExtraTables)); # placeholders for stateSize, classTable, stateArray, entryTable
+
+ my ($firstGlyph, $lastGlyph) = (0xffff, 0, 0);
+ my (@classTable, $i);
+ foreach $i (0 .. $#$classes) {
+ my $class = $classes->[$i];
+ foreach (@$class) {
+ $firstGlyph = $_ if $_ < $firstGlyph;
+ $lastGlyph = $_ if $_ > $lastGlyph;
+ $classTable[$_] = $i;
+ }
+ }
+
+ my $classTable = length($dat);
+ $dat .= pack("nnC*", $firstGlyph, $lastGlyph - $firstGlyph + 1,
+ map { defined $classTable[$_] ? $classTable[$_] : 1 } ($firstGlyph .. $lastGlyph));
+ $dat .= pack("C", 0) if (($lastGlyph - $firstGlyph) & 1) == 0; # pad if odd number of glyphs
+
+ my $stateArray = length($dat);
+ my (@entries, %entries);
+ my $state = $states->[0];
+ my $stateSize = @$state;
+ die "stateSize below minimum allowed (4)" if $stateSize < 4;
+ die "stateSize (" . $stateSize . ") too small for max class number (" . $#$classes . ")" if $stateSize < $#$classes + 1;
+ warn "state array has unreachable columns" if $stateSize > $#$classes + 1;
+
+ foreach (@$states) {
+ die "inconsistent state size" if @$_ != $stateSize;
+ foreach (@$_) {
+ my $actions = $_->{'actions'};
+ my $entry = join(",", $stateArray + $_->{'nextState'} * $stateSize, $_->{'flags'}, ref($actions) eq 'ARRAY' ? @$actions : $actions);
+ if (not defined $entries{$entry}) {
+ push @entries, $entry;
+ $entries{$entry} = $#entries;
+ die "too many different state array entries" if $#entries == 256;
+ }
+ $dat .= pack("C", $entries{$entry});
+ }
+ }
+ $dat .= pack("C", 0) if (@$states & 1) != 0 and ($stateSize & 1) != 0; # pad if state array size is odd
+
+ my $entryTable = length($dat);
+ $dat .= map { &$packEntry($_, $entryTable, $#entries + 1) } @entries;
+
+ my ($dat1) = pack("nnnn", $stateSize, $classTable, $stateArray, $entryTable);
+ substr($dat, 0, length($dat1)) = $dat1;
+
+ return $dat;
+}
+
+sub AAT_write_state_table
+{
+ my ($fh, $classes, $states, $numExtraTables, $packEntry) = @_;
+
+ my $stateTableStart = $fh->tell();
+
+ $fh->print(pack("n*", (0) x (4 + $numExtraTables))); # placeholders for stateSize, classTable, stateArray, entryTable
+
+ my ($firstGlyph, $lastGlyph) = (0xffff, 0, 0);
+ my (@classTable, $i);
+ foreach $i (0 .. $#$classes) {
+ my $class = $classes->[$i];
+ foreach (@$class) {
+ $firstGlyph = $_ if $_ < $firstGlyph;
+ $lastGlyph = $_ if $_ > $lastGlyph;
+ $classTable[$_] = $i;
+ }
+ }
+
+ my $classTable = $fh->tell() - $stateTableStart;
+ $fh->print(pack("nnC*", $firstGlyph, $lastGlyph - $firstGlyph + 1,
+ map { defined $classTable[$_] ? $classTable[$_] : 1 } ($firstGlyph .. $lastGlyph)));
+ $fh->print(pack("C", 0)) if (($lastGlyph - $firstGlyph) & 1) == 0; # pad if odd number of glyphs
+
+ my $stateArray = $fh->tell() - $stateTableStart;
+ my (@entries, %entries);
+ my $state = $states->[0];
+ my $stateSize = @$state;
+ die "stateSize below minimum allowed (4)" if $stateSize < 4;
+ die "stateSize (" . $stateSize . ") too small for max class number (" . $#$classes . ")" if $stateSize < $#$classes + 1;
+ warn "state array has unreachable columns" if $stateSize > $#$classes + 1;
+
+ foreach (@$states) {
+ die "inconsistent state size" if @$_ != $stateSize;
+ foreach (@$_) {
+ my $actions = $_->{'actions'};
+ my $entry = join(",", $stateArray + $_->{'nextState'} * $stateSize, $_->{'flags'}, ref($actions) eq 'ARRAY' ? @$actions : $actions);
+ if (not defined $entries{$entry}) {
+ push @entries, $entry;
+ $entries{$entry} = $#entries;
+ die "too many different state array entries" if $#entries == 256;
+ }
+ $fh->print(pack("C", $entries{$entry}));
+ }
+ }
+ $fh->print(pack("C", 0)) if (@$states & 1) != 0 and ($stateSize & 1) != 0; # pad if state array size is odd
+
+ my $entryTable = $fh->tell() - $stateTableStart;
+ $fh->print(map { &$packEntry($_, $entryTable, $#entries + 1) } @entries);
+
+ my $length = $fh->tell() - $stateTableStart;
+ $fh->seek($stateTableStart, IO::File::SEEK_SET);
+ $fh->print(pack("nnnn", $stateSize, $classTable, $stateArray, $entryTable));
+
+ $fh->seek($stateTableStart + $length, IO::File::SEEK_SET);
+ $length;
+}
+
+sub AAT_pack_classes
+{
+ my ($classes) = @_;
+
+ my ($firstGlyph, $lastGlyph) = (0xffff, 0, 0);
+ my (@classTable, $i);
+ foreach $i (0 .. $#$classes) {
+ my $class = $classes->[$i];
+ foreach (@$class) {
+ $firstGlyph = $_ if $_ < $firstGlyph;
+ $lastGlyph = $_ if $_ > $lastGlyph;
+ $classTable[$_] = $i;
+ }
+ }
+
+ my ($dat) = pack("nnC*", $firstGlyph, $lastGlyph - $firstGlyph + 1,
+ map { defined $classTable[$_] ? $classTable[$_] : 1 } ($firstGlyph .. $lastGlyph));
+ $dat .= pack("C", 0) if (($lastGlyph - $firstGlyph) & 1) == 0; # pad if odd number of glyphs
+
+ return $dat;
+}
+
+sub AAT_write_classes
+{
+ my ($fh, $classes) = @_;
+
+ $fh->print(AAT_pack_classes($fh, $classes));
+}
+
+sub AAT_pack_states
+{
+ my ($classes, $stateArray, $states, $buildEntryProc) = @_;
+
+ my ($entries, %entryHash);
+ my $state = $states->[0];
+ my $stateSize = @$state;
+
+ die "stateSize below minimum allowed (4)" if $stateSize < 4;
+ die "stateSize (" . $stateSize . ") too small for max class number (" . $#$classes . ")" if $stateSize < $#$classes + 1;
+ warn "state array has unreachable columns" if $stateSize > $#$classes + 1;
+
+ my ($dat);
+ foreach (@$states) {
+ die "inconsistent state size" if @$_ != $stateSize;
+ foreach (@$_) {
+ my $entry = join(",", $stateArray + $_->{'nextState'} * $stateSize, &$buildEntryProc($_));
+ if (not defined $entryHash{$entry}) {
+ push @$entries, $entry;
+ $entryHash{$entry} = $#$entries;
+ die "too many different state array entries" if $#$entries == 256;
+ }
+ $dat .= pack("C", $entryHash{$entry});
+ }
+ }
+ $dat .= pack("C", 0) if (@$states & 1) != 0 and ($stateSize & 1) != 0; # pad if state array size is odd
+
+ ($dat, $stateSize, $entries);
+}
+
+sub AAT_write_states
+{
+ my ($fh, $classes, $stateArray, $states, $buildEntryProc) = @_;
+
+ my ($entries, %entryHash);
+ my $state = $states->[0];
+ my $stateSize = @$state;
+
+ die "stateSize below minimum allowed (4)" if $stateSize < 4;
+ die "stateSize (" . $stateSize . ") too small for max class number (" . $#$classes . ")" if $stateSize < $#$classes + 1;
+ warn "state array has unreachable columns" if $stateSize > $#$classes + 1;
+
+ foreach (@$states) {
+ die "inconsistent state size" if @$_ != $stateSize;
+ foreach (@$_) {
+ my $entry = join(",", $stateArray + $_->{'nextState'} * $stateSize, &$buildEntryProc($_));
+ if (not defined $entryHash{$entry}) {
+ push @$entries, $entry;
+ $entryHash{$entry} = $#$entries;
+ die "too many different state array entries" if $#$entries == 256;
+ }
+ $fh->print(pack("C", $entryHash{$entry}));
+ }
+ }
+ $fh->print(pack("C", 0)) if (@$states & 1) != 0 and ($stateSize & 1) != 0; # pad if state array size is odd
+
+ ($stateSize, $entries);
+}
+
+=head2 ($classes, $states, $entries) = AAT_read_state_table($fh, $numActionWords)
+
+=cut
+
+sub AAT_read_state_table
+{
+ my ($fh, $numActionWords) = @_;
+
+ my $stateTableStart = $fh->tell();
+ my $dat;
+ $fh->read($dat, 8);
+ my ($stateSize, $classTable, $stateArray, $entryTable) = unpack("nnnn", $dat);
+
+ my $classes; # array of lists of glyphs
+
+ $fh->seek($stateTableStart + $classTable, IO::File::SEEK_SET);
+ $fh->read($dat, 4);
+ my ($firstGlyph, $nGlyphs) = unpack("nn", $dat);
+ $fh->read($dat, $nGlyphs);
+ foreach (unpack("C*", $dat)) {
+ if ($_ != 1) {
+ my $class = $classes->[$_];
+ push(@$class, $firstGlyph);
+ $classes->[$_] = $class unless defined $classes->[$_];
+ }
+ $firstGlyph++;
+ }
+
+ $fh->seek($stateTableStart + $stateArray, IO::File::SEEK_SET);
+ my $states; # array of arrays of hashes{nextState, flags, actions}
+
+ my $entrySize = 4 + ($numActionWords * 2);
+ my $lastState = 1;
+ my $entries;
+ while ($#$states < $lastState) {
+ $fh->read($dat, $stateSize);
+ my @stateEntries = unpack("C*", $dat);
+ my $state;
+ foreach (@stateEntries) {
+ if (not defined $entries->[$_]) {
+ my $loc = $fh->tell();
+ $fh->seek($stateTableStart + $entryTable + ($_ * $entrySize), IO::File::SEEK_SET);
+ $fh->read($dat, $entrySize);
+ my ($nextState, $flags, $actions);
+ ($nextState, $flags, @$actions) = unpack("n*", $dat);
+ $nextState -= $stateArray;
+ $nextState /= $stateSize;
+ $entries->[$_] = { 'nextState' => $nextState, 'flags' => $flags };
+ $entries->[$_]->{'actions'} = $actions if $numActionWords > 0;
+ $lastState = $nextState if ($nextState > $lastState);
+ $fh->seek($loc, IO::File::SEEK_SET);
+ }
+ push(@$state, $entries->[$_]);
+ }
+ push(@$states, $state);
+ }
+
+ ($classes, $states, $entries);
+}
+
+=head2 ($format, $lookup) = AAT_read_lookup($fh, $valueSize, $length, $default)
+
+=cut
+
+sub AAT_read_lookup
+{
+ my ($fh, $valueSize, $length, $default) = @_;
+
+ my $lookupStart = $fh->tell();
+ my ($dat, $unpackChar);
+ if ($valueSize == 1) {
+ $unpackChar = "C";
+ }
+ elsif ($valueSize == 2) {
+ $unpackChar = "n";
+ }
+ elsif ($valueSize == 4) {
+ $unpackChar = "N";
+ }
+ else {
+ die "unsupported value size";
+ }
+
+ $fh->read($dat, 2);
+ my $format = unpack("n", $dat);
+ my $lookup;
+
+ if ($format == 0) {
+ $fh->read($dat, $length - 2);
+ my $i = -1;
+ $lookup = { map { $i++; ($_ != $default) ? ($i, $_) : () } unpack($unpackChar . "*", $dat) };
+ }
+
+ elsif ($format == 2) {
+ $fh->read($dat, 10);
+ my ($unitSize, $nUnits, $searchRange, $entrySelector, $rangeShift) = unpack("nnnnn", $dat);
+ die if $unitSize != 4 + $valueSize;
+ foreach (1 .. $nUnits) {
+ $fh->read($dat, $unitSize);
+ my ($lastGlyph, $firstGlyph, $value) = unpack("nn" . $unpackChar, $dat);
+ if ($firstGlyph != 0xffff and $value != $default) {
+ foreach ($firstGlyph .. $lastGlyph) {
+ $lookup->{$_} = $value;
+ }
+ }
+ }
+ }
+
+ elsif ($format == 4) {
+ $fh->read($dat, 10);
+ my ($unitSize, $nUnits, $searchRange, $entrySelector, $rangeShift) = unpack("nnnnn", $dat);
+ die if $unitSize != 6;
+ foreach (1 .. $nUnits) {
+ $fh->read($dat, $unitSize);
+ my ($lastGlyph, $firstGlyph, $offset) = unpack("nnn", $dat);
+ if ($firstGlyph != 0xffff) {
+ my $loc = $fh->tell();
+ $fh->seek($lookupStart + $offset, IO::File::SEEK_SET);
+ $fh->read($dat, ($lastGlyph - $firstGlyph + 1) * $valueSize);
+ my @values = unpack($unpackChar . "*", $dat);
+ foreach (0 .. $lastGlyph - $firstGlyph) {
+ $lookup->{$firstGlyph + $_} = $values[$_] if $values[$_] != $default;
+ }
+ $fh->seek($loc, IO::File::SEEK_SET);
+ }
+ }
+ }
+
+ elsif ($format == 6) {
+ $fh->read($dat, 10);
+ my ($unitSize, $nUnits, $searchRange, $entrySelector, $rangeShift) = unpack("nnnnn", $dat);
+ die if $unitSize != 2 + $valueSize;
+ foreach (1 .. $nUnits) {
+ $fh->read($dat, $unitSize);
+ my ($glyph, $value) = unpack("n" . $unpackChar, $dat);
+ $lookup->{$glyph} = $value if $glyph != 0xffff and $value != $default;
+ }
+ }
+
+ elsif ($format == 8) {
+ $fh->read($dat, 4);
+ my ($firstGlyph, $glyphCount) = unpack("nn", $dat);
+ $fh->read($dat, $glyphCount * $valueSize);
+ $firstGlyph--;
+ $lookup = { map { $firstGlyph++; $_ != $default ? ($firstGlyph, $_) : () } unpack($unpackChar . "*", $dat) };
+ }
+
+ else {
+ die "unknown lookup format";
+ }
+
+ $fh->seek($lookupStart + $length, IO::File::SEEK_SET);
+
+ ($format, $lookup);
+}
+
+=head2 AAT_write_lookup($fh, $format, $lookup, $valueSize, $default)
+
+=cut
+
+sub AAT_pack_lookup
+{
+ my ($format, $lookup, $valueSize, $default) = @_;
+
+ my $packChar;
+ if ($valueSize == 1) {
+ $packChar = "C";
+ }
+ elsif ($valueSize == 2) {
+ $packChar = "n";
+ }
+ elsif ($valueSize == 4) {
+ $packChar = "N";
+ }
+ else {
+ die "unsupported value size";
+ }
+
+ my ($dat) = pack("n", $format);
+
+ my ($firstGlyph, $lastGlyph) = (0xffff, 0);
+ foreach (keys %$lookup) {
+ $firstGlyph = $_ if $_ < $firstGlyph;
+ $lastGlyph = $_ if $_ > $lastGlyph;
+ }
+ my $glyphCount = $lastGlyph - $firstGlyph + 1;
+
+ if ($format == 0) {
+ $dat .= pack($packChar . "*", map { defined $lookup->{$_} ? $lookup->{$_} : defined $default ? $default : $_ } (0 .. $lastGlyph));
+ }
+
+ elsif ($format == 2) {
+ my $prev = $default;
+ my $segStart = $firstGlyph;
+ my $dat1;
+ foreach ($firstGlyph .. $lastGlyph + 1) {
+ my $val = $lookup->{$_};
+ $val = $default unless defined $val;
+ if ($val != $prev) {
+ $dat1 .= pack("nn" . $packChar, $_ - 1, $segStart, $prev) if $prev != $default;
+ $prev = $val;
+ $segStart = $_;
+ }
+ }
+ $dat1 .= pack("nn" . $packChar, 0xffff, 0xffff, 0);
+ my $unitSize = 4 + $valueSize;
+ $dat .= pack("nnnnn", $unitSize, TTF_bininfo(length($dat1) / $unitSize, $unitSize));
+ $dat .= $dat1;
+ }
+
+ elsif ($format == 4) {
+ my $segArray = new Font::TTF::Segarr($valueSize);
+ $segArray->add_segment($firstGlyph, 1, map { $lookup->{$_} } ($firstGlyph .. $lastGlyph));
+ my ($start, $end, $offset);
+ $offset = 12 + @$segArray * 6 + 6; # 12 is size of format word + binSearchHeader; 6 bytes per segment; 6 for terminating segment
+ my $dat1;
+ foreach (@$segArray) {
+ $start = $_->{'START'};
+ $end = $start + $_->{'LEN'} - 1;
+ $dat1 .= pack("nnn", $end, $start, $offset);
+ $offset += $_->{'LEN'} * 2;
+ }
+ $dat1 .= pack("nnn", 0xffff, 0xffff, 0);
+ $dat .= pack("nnnnn", 6, TTF_bininfo(length($dat1) / 6, 6));
+ $dat .= $dat1;
+ foreach (@$segArray) {
+ $dat1 = $_->{'VAL'};
+ $dat .= pack($packChar . "*", @$dat1);
+ }
+ }
+
+ elsif ($format == 6) {
+ die "unsupported" if $valueSize != 2;
+ my $dat1 = pack("n*", map { $_, $lookup->{$_} } sort { $a <=> $b } grep { $lookup->{$_} ne $default } keys %$lookup);
+ my $unitSize = 2 + $valueSize;
+ $dat .= pack("nnnnn", $unitSize, TTF_bininfo(length($dat1) / $unitSize, $unitSize));
+ $dat .= $dat1;
+ }
+
+ elsif ($format == 8) {
+ $dat .= pack("nn", $firstGlyph, $lastGlyph - $firstGlyph + 1);
+ $dat .= pack($packChar . "*", map { defined $lookup->{$_} ? $lookup->{$_} : defined $default ? $default : $_ } ($firstGlyph .. $lastGlyph));
+ }
+
+ else {
+ die "unknown lookup format";
+ }
+
+ my $padBytes = (4 - (length($dat) & 3)) & 3;
+ $dat .= pack("C*", (0) x $padBytes);
+
+ return $dat;
+}
+
+sub AAT_write_lookup
+{
+ my ($fh, $format, $lookup, $valueSize, $default) = @_;
+
+ my $lookupStart = $fh->tell();
+ my $packChar;
+ if ($valueSize == 1) {
+ $packChar = "C";
+ }
+ elsif ($valueSize == 2) {
+ $packChar = "n";
+ }
+ elsif ($valueSize == 4) {
+ $packChar = "N";
+ }
+ else {
+ die "unsupported value size";
+ }
+
+ $fh->print(pack("n", $format));
+
+ my ($firstGlyph, $lastGlyph) = (0xffff, 0);
+ foreach (keys %$lookup) {
+ $firstGlyph = $_ if $_ < $firstGlyph;
+ $lastGlyph = $_ if $_ > $lastGlyph;
+ }
+ my $glyphCount = $lastGlyph - $firstGlyph + 1;
+
+ if ($format == 0) {
+ $fh->print(pack($packChar . "*", map { defined $lookup->{$_} ? $lookup->{$_} : defined $default ? $default : $_ } (0 .. $lastGlyph)));
+ }
+
+ elsif ($format == 2) {
+ my $prev = $default;
+ my $segStart = $firstGlyph;
+ my $dat;
+ foreach ($firstGlyph .. $lastGlyph + 1) {
+ my $val = $lookup->{$_};
+ $val = $default unless defined $val;
+ if ($val != $prev) {
+ $dat .= pack("nn" . $packChar, $_ - 1, $segStart, $prev) if $prev != $default;
+ $prev = $val;
+ $segStart = $_;
+ }
+ }
+ $dat .= pack("nn" . $packChar, 0xffff, 0xffff, 0);
+ my $unitSize = 4 + $valueSize;
+ $fh->print(pack("nnnnn", $unitSize, TTF_bininfo(length($dat) / $unitSize, $unitSize)));
+ $fh->print($dat);
+ }
+
+ elsif ($format == 4) {
+ my $segArray = new Font::TTF::Segarr($valueSize);
+ $segArray->add_segment($firstGlyph, 1, map { $lookup->{$_} } ($firstGlyph .. $lastGlyph));
+ my ($start, $end, $offset);
+ $offset = 12 + @$segArray * 6 + 6; # 12 is size of format word + binSearchHeader; 6 bytes per segment; 6 for terminating segment
+ my $dat;
+ foreach (@$segArray) {
+ $start = $_->{'START'};
+ $end = $start + $_->{'LEN'} - 1;
+ $dat .= pack("nnn", $end, $start, $offset);
+ $offset += $_->{'LEN'} * 2;
+ }
+ $dat .= pack("nnn", 0xffff, 0xffff, 0);
+ $fh->print(pack("nnnnn", 6, TTF_bininfo(length($dat) / 6, 6)));
+ $fh->print($dat);
+ foreach (@$segArray) {
+ $dat = $_->{'VAL'};
+ $fh->print(pack($packChar . "*", @$dat));
+ }
+ }
+
+ elsif ($format == 6) {
+ die "unsupported" if $valueSize != 2;
+ my $dat = pack("n*", map { $_, $lookup->{$_} } sort { $a <=> $b } grep { $lookup->{$_} ne $default } keys %$lookup);
+ my $unitSize = 2 + $valueSize;
+ $fh->print(pack("nnnnn", $unitSize, TTF_bininfo(length($dat) / $unitSize, $unitSize)));
+ $fh->print($dat);
+ }
+
+ elsif ($format == 8) {
+ $fh->print(pack("nn", $firstGlyph, $lastGlyph - $firstGlyph + 1));
+ $fh->print(pack($packChar . "*", map { defined $lookup->{$_} ? $lookup->{$_} : defined $default ? $default : $_ } ($firstGlyph .. $lastGlyph)));
+ }
+
+ else {
+ die "unknown lookup format";
+ }
+
+ my $length = $fh->tell() - $lookupStart;
+ my $padBytes = (4 - ($length & 3)) & 3;
+ $fh->print(pack("C*", (0) x $padBytes));
+ $length += $padBytes;
+
+ $length;
+}
+
+1;
+
Modified: packages/libfont-ttf-perl/trunk/lib/Font/TTF/Anchor.pm
===================================================================
--- packages/libfont-ttf-perl/trunk/lib/Font/TTF/Anchor.pm 2006-01-17 02:56:43 UTC (rev 1966)
+++ packages/libfont-ttf-perl/trunk/lib/Font/TTF/Anchor.pm 2006-01-17 03:07:20 UTC (rev 1967)
@@ -1,208 +1,208 @@
-package Font::TTF::Anchor;
-
-=head1 NAME
-
-Font::TTF::Anchor - Anchor points for GPOS tables
-
-=head1 DESCRIPTION
-
-The Anchor defines an anchor point on a glyph providing various information
-depending on how much is available, including such information as the co-ordinates,
-a curve point and even device specific modifiers.
-
-=head1 INSTANCE VARIABLES
-
-=over 4
-
-=item x
-
-XCoordinate of the anchor point
-
-=item y
-
-YCoordinate of the anchor point
-
-=item p
-
-Curve point on the glyph to use as the anchor point
-
-=item xdev
-
-Device table (delta) for the xcoordinate
-
-=item ydev
-
-Device table (delta) for the ycoordinate
-
-=item xid
-
-XIdAnchor for multiple master horizontal metric id
-
-=item yid
-
-YIdAnchor for multiple master vertical metric id
-
-=back
-
-=head1 METHODS
-
-=cut
-
-use strict;
-
-
-=head2 new
-
-Creates a new Anchor
-
-=cut
-
-sub new
-{
- my ($class) = shift;
- my ($self) = {@_};
-
- bless $self, $class;
-}
-
-
-=head2 read($fh)
-
-Reads the anchor from the given file handle at that point. The file handle is left
-at an arbitrary read point, usually the end of something!
-
-=cut
-
-sub read
-{
- my ($self, $fh) = @_;
- my ($dat, $loc, $fmt, $x, $y, $p, $xoff, $yoff);
-
- $fh->read($dat, 6);
- ($fmt, $x, $y) = unpack('n*', $dat);
- if ($fmt == 4)
- { ($self->{'xid'}, $self->{'yid'}) = ($x, $y); }
- else
- { ($self->{'x'}, $self->{'y'}) = ($x, $y); }
-
- if ($fmt == 2)
- {
- $fh->read($dat, 2);
- $self->{'p'} = unpack('n', $dat);
- } elsif ($fmt == 3)
- {
- $fh->read($dat, 4);
- ($xoff, $yoff) = unpack('n2', $dat);
- $loc = $fh->tell() - 10;
- if ($xoff)
- {
- $fh->seek($loc + $xoff, 0);
- $self->{'xdev'} = Font::TTF::Delta->new->read($fh);
- }
- if ($yoff)
- {
- $fh->seek($loc + $yoff, 0);
- $self->{'ydev'} = Font::TTF::Delta->new->read($fh);
- }
- }
- $self;
-}
-
-
-=head2 out($fh, $style)
-
-Outputs the Anchor to the given file handle at this point also addressing issues
-of deltas. If $style is set, then no output is set to the file handle. The return
-value is the output string.
-
-=cut
-
-sub out
-{
- my ($self, $fh, $style) = @_;
- my ($xoff, $yoff, $fmt, $out);
-
- if (defined $self->{'xid'} || defined $self->{'yid'})
- { $out = pack('n*', 4, $self->{'xid'}, $self->{'yid'}); }
- elsif (defined $self->{'p'})
- { $out = pack('n*', 2, @{$self}{'x', 'y', 'p'}); }
- elsif (defined $self->{'xdev'} || defined $self->{'ydev'})
- {
- $out = pack('n*', 3, @{$self}{'x', 'y'});
- if (defined $self->{'xdev'})
- {
- $out .= pack('n2', 10, 0);
- $out .= $self->{'xdev'}->out($fh, 1);
- $yoff = length($out) - 10;
- }
- else
- { $out .= pack('n2', 0, 0); }
- if (defined $self->{'ydev'})
- {
- $yoff = 10 unless $yoff;
- substr($out, 8, 2) = pack('n', $yoff);
- $out .= $self->{'ydev'}->out($fh, 1);
- }
- } else
- { $out = pack('n3', 1, @{$self}{'x', 'y'}); }
- $fh->print($out) unless $style;
- $out;
-}
-
-
-=head2 $a->out_xml($context)
-
-Outputs the anchor in XML
-
-=cut
-
-sub out_xml
-{
- my ($self, $context, $depth) = @_;
- my ($fh) = $context->{'fh'};
- my ($end);
-
- $fh->print("$depth<anchor x='$self->{'x'}' y='$self->{'y'}'");
- $fh->print(" p='$self->{'p'}'") if defined ($self->{'p'});
- $end = (defined $self->{'xdev'} || defined $self->{'ydev'} || defined $self->{'xid'} || defined $self->{'yid'});
- unless ($end)
- {
- $fh->print("/>\n");
- return $self;
- }
-
- if (defined $self->{'xdev'})
- {
- $fh->print("$depth$context->{'indent'}<xdev>\n");
- $self->{'xdev'}->out_xml($context, $depth . ($context->{'indent'} x 2));
- $fh->print("$depth$context->{'indent'}</xdev>\n");
- }
-
- if (defined $self->{'ydev'})
- {
- $fh->print("$depth$context->{'indent'}<ydev>\n");
- $self->{'ydev'}->out_xml($context, $depth . ($context->{'indent'} x 2));
- $fh->print("$depth$context->{'indent'}</ydev>\n");
- }
-
- if (defined $self->{'xid'} || defined $self->{'yid'})
- {
- $fh->print("$depth$context->{'indent'}<mmaster");
- $fh->print(" xid='$self->{'xid'}'") if defined ($self->{'xid'});
- $fh->print(" yid='$self->{'yid'}'") if defined ($self->{'yid'});
- $fh->print("/>\n");
- }
- $fh->print("$depth</anchor>\n");
- $self;
-}
-
-
-=head1 AUTHOR
-
-Martin Hosken Martin_Hosken at sil.org. See L<Font::TTF::Font> for copyright and
-licensing.
-
-=cut
-
-1;
-
+package Font::TTF::Anchor;
+
+=head1 TITLE
+
+Font::TTF::Anchor - Anchor points for GPOS tables
+
+=head1 DESCRIPTION
+
+The Anchor defines an anchor point on a glyph providing various information
+depending on how much is available, including such information as the co-ordinates,
+a curve point and even device specific modifiers.
+
+=head1 INSTANCE VARIABLES
+
+=over 4
+
+=item x
+
+XCoordinate of the anchor point
+
+=item y
+
+YCoordinate of the anchor point
+
+=item p
+
+Curve point on the glyph to use as the anchor point
+
+=item xdev
+
+Device table (delta) for the xcoordinate
+
+=item ydev
+
+Device table (delta) for the ycoordinate
+
+=item xid
+
+XIdAnchor for multiple master horizontal metric id
+
+=item yid
+
+YIdAnchor for multiple master vertical metric id
+
+=back
+
+=head1 METHODS
+
+=cut
+
+use strict;
+
+
+=head2 new
+
+Creates a new Anchor
+
+=cut
+
+sub new
+{
+ my ($class) = shift;
+ my ($self) = {@_};
+
+ bless $self, $class;
+}
+
+
+=head2 read($fh)
+
+Reads the anchor from the given file handle at that point. The file handle is left
+at an arbitrary read point, usually the end of something!
+
+=cut
+
+sub read
+{
+ my ($self, $fh) = @_;
+ my ($dat, $loc, $fmt, $x, $y, $p, $xoff, $yoff);
+
+ $fh->read($dat, 6);
+ ($fmt, $x, $y) = unpack('n*', $dat);
+ if ($fmt == 4)
+ { ($self->{'xid'}, $self->{'yid'}) = ($x, $y); }
+ else
+ { ($self->{'x'}, $self->{'y'}) = ($x, $y); }
+
+ if ($fmt == 2)
+ {
+ $fh->read($dat, 2);
+ $self->{'p'} = unpack('n', $dat);
+ } elsif ($fmt == 3)
+ {
+ $fh->read($dat, 4);
+ ($xoff, $yoff) = unpack('n2', $dat);
+ $loc = $fh->tell() - 10;
+ if ($xoff)
+ {
+ $fh->seek($loc + $xoff, 0);
+ $self->{'xdev'} = Font::TTF::Delta->new->read($fh);
+ }
+ if ($yoff)
+ {
+ $fh->seek($loc + $yoff, 0);
+ $self->{'ydev'} = Font::TTF::Delta->new->read($fh);
+ }
+ }
+ $self;
+}
+
+
+=head2 out($fh, $style)
+
+Outputs the Anchor to the given file handle at this point also addressing issues
+of deltas. If $style is set, then no output is set to the file handle. The return
+value is the output string.
+
+=cut
+
+sub out
+{
+ my ($self, $fh, $style) = @_;
+ my ($xoff, $yoff, $fmt, $out);
+
+ if (defined $self->{'xid'} || defined $self->{'yid'})
+ { $out = pack('n*', 4, $self->{'xid'}, $self->{'yid'}); }
+ elsif (defined $self->{'p'})
+ { $out = pack('n*', 2, @{$self}{'x', 'y', 'p'}); }
+ elsif (defined $self->{'xdev'} || defined $self->{'ydev'})
+ {
+ $out = pack('n*', 3, @{$self}{'x', 'y'});
+ if (defined $self->{'xdev'})
+ {
+ $out .= pack('n2', 10, 0);
+ $out .= $self->{'xdev'}->out($fh, 1);
+ $yoff = length($out) - 10;
+ }
+ else
+ { $out .= pack('n2', 0, 0); }
+ if (defined $self->{'ydev'})
+ {
+ $yoff = 10 unless $yoff;
+ substr($out, 8, 2) = pack('n', $yoff);
+ $out .= $self->{'ydev'}->out($fh, 1);
+ }
+ } else
+ { $out = pack('n3', 1, @{$self}{'x', 'y'}); }
+ $fh->print($out) unless $style;
+ $out;
+}
+
+
+=head2 $a->out_xml($context)
+
+Outputs the anchor in XML
+
+=cut
+
+sub out_xml
+{
+ my ($self, $context, $depth) = @_;
+ my ($fh) = $context->{'fh'};
+ my ($end);
+
+ $fh->print("$depth<anchor x='$self->{'x'}' y='$self->{'y'}'");
+ $fh->print(" p='$self->{'p'}'") if defined ($self->{'p'});
+ $end = (defined $self->{'xdev'} || defined $self->{'ydev'} || defined $self->{'xid'} || defined $self->{'yid'});
+ unless ($end)
+ {
+ $fh->print("/>\n");
+ return $self;
+ }
+
+ if (defined $self->{'xdev'})
+ {
+ $fh->print("$depth$context->{'indent'}<xdev>\n");
+ $self->{'xdev'}->out_xml($context, $depth . ($context->{'indent'} x 2));
+ $fh->print("$depth$context->{'indent'}</xdev>\n");
+ }
+
+ if (defined $self->{'ydev'})
+ {
+ $fh->print("$depth$context->{'indent'}<ydev>\n");
+ $self->{'ydev'}->out_xml($context, $depth . ($context->{'indent'} x 2));
+ $fh->print("$depth$context->{'indent'}</ydev>\n");
+ }
+
+ if (defined $self->{'xid'} || defined $self->{'yid'})
+ {
+ $fh->print("$depth$context->{'indent'}<mmaster");
+ $fh->print(" xid='$self->{'xid'}'") if defined ($self->{'xid'});
+ $fh->print(" yid='$self->{'yid'}'") if defined ($self->{'yid'});
+ $fh->print("/>\n");
+ }
+ $fh->print("$depth</anchor>\n");
+ $self;
+}
+
+
+=head1 AUTHOR
+
+Martin Hosken Martin_Hosken at sil.org. See L<Font::TTF::Font> for copyright and
+licensing.
+
+=cut
+
+1;
+
Modified: packages/libfont-ttf-perl/trunk/lib/Font/TTF/Bsln.pm
===================================================================
--- packages/libfont-ttf-perl/trunk/lib/Font/TTF/Bsln.pm 2006-01-17 02:56:43 UTC (rev 1966)
+++ packages/libfont-ttf-perl/trunk/lib/Font/TTF/Bsln.pm 2006-01-17 03:07:20 UTC (rev 1967)
@@ -1,163 +1,163 @@
-package Font::TTF::Bsln;
-
-=head1 NAME
-
-Font::TTF::Bsln - Baseline table in a font
-
-=head1 DESCRIPTION
-
-=head1 INSTANCE VARIABLES
-
-=item version
-
-=item xformat
-
-=item defaultBaseline
-
-=item deltas
-
-=item stdGlyph
-
-=item ctlPoints
-
-=item lookupFormat
-
-=item lookup
-
-=head1 METHODS
-
-=cut
-
-use strict;
-use vars qw(@ISA);
-
-use Font::TTF::AATutils;
-use Font::TTF::Utils;
-require Font::TTF::Table;
-
- at ISA = qw(Font::TTF::Table);
-
-=head2 $t->read
-
-Reads the table into memory
-
-=cut
-
-sub read
-{
- my ($self) = @_;
- my ($dat, $fh);
-
- $self->SUPER::read or return $self;
-
- $fh = $self->{' INFILE'};
- $fh->read($dat, 8);
- my ($version, $format, $defaultBaseline) = TTF_Unpack("fSS", $dat);
-
- if ($format == 0 or $format == 1) {
- $fh->read($dat, 64);
- $self->{'deltas'} = [TTF_Unpack("s*", $dat)];
- }
- elsif ($format == 2 or $format == 3) {
- $fh->read($dat, 2);
- $self->{'stdGlyph'} = unpack("n", $dat);
- $fh->read($dat, 64);
- $self->{'ctlPoints'} = unpack("n*", $dat);
- }
- else {
- die "unknown table format";
- }
-
- if ($format == 1 or $format == 3) {
- my $len = $self->{' LENGTH'} - ($fh->tell() - $self->{' OFFSET'});
- my ($lookupFormat, $lookup) = AAT_read_lookup($fh, 2, $len, $defaultBaseline);
- $self->{'lookupFormat'} = $lookupFormat;
- $self->{'lookup'} = $lookup;
- }
-
- $self->{'version'} = $version;
- $self->{'format'} = $format;
- $self->{'defaultBaseline'} = $defaultBaseline;
-
- $self;
-}
-
-=head2 $t->out($fh)
-
-Writes the table to a file either from memory or by copying
-
-=cut
-
-sub out
-{
- my ($self, $fh) = @_;
-
- return $self->SUPER::out($fh) unless $self->{' read'};
-
- my $format = $self->{'format'};
- my $defaultBaseline = $self->{'defaultBaseline'};
- $fh->print(TTF_Pack("fSS", $self->{'version'}, $format, $defaultBaseline));
-
- AAT_write_lookup($fh, $self->{'lookupFormat'}, $self->{'lookup'}, 2, $defaultBaseline) if ($format == 1 or $format == 3);
-}
-
-=head2 $t->print($fh)
-
-Prints a human-readable representation of the table
-
-=cut
-
-sub print
-{
- my ($self, $fh) = @_;
-
- $self->read;
-
- $fh = 'STDOUT' unless defined $fh;
-
- my $format = $self->{'format'};
- $fh->printf("version %f\nformat %d\ndefaultBaseline %d\n", $self->{'version'}, $format, $self->{'defaultBaseline'});
- if ($format == 0 or $format == 1) {
- $fh->printf("\tdeltas:\n");
- my $deltas = $self->{'deltas'};
- foreach (0 .. 31) {
- $fh->printf("\t\t%d: %d%s\n", $_, $deltas->[$_], defined baselineName_($_) ? "\t# " . baselineName_($_) : "");
- }
- }
- if ($format == 2 or $format == 3) {
- $fh->printf("\tstdGlyph = %d\n", $self->{'stdGlyph'});
- my $ctlPoints = $self->{'ctlPoints'};
- foreach (0 .. 31) {
- $fh->printf("\t\t%d: %d%s\n", $_, $ctlPoints->[$_], defined baselineName_($_) ? "\t# " . baselineName_($_) : "");
- }
- }
- if ($format == 1 or $format == 3) {
- $fh->printf("lookupFormat %d\n", $self->{'lookupFormat'});
- my $lookup = $self->{'lookup'};
- foreach (sort { $a <=> $b } keys %$lookup) {
- $fh->printf("\tglyph %d: %d%s\n", $_, $lookup->{$_}, defined baselineName_($_) ? "\t# " . baselineName_($_) : "");
- }
- }
-}
-
-sub baselineName_
-{
- my ($b) = @_;
- my @baselines = ( 'Roman', 'Ideographic centered', 'Ideographic low', 'Hanging', 'Math' );
- $baselines[$b];
-}
-
-1;
-
-
-=head1 BUGS
-
-None known
-
-=head1 AUTHOR
-
-Jonathan Kew L<Jonathan_Kew at sil.org>. See L<Font::TTF::Font> for copyright and
-licensing.
-
-=cut
-
+package Font::TTF::Bsln;
+
+=head1 NAME
+
+Font::TTF::Bsln - Baseline table in a font
+
+=head1 DESCRIPTION
+
+=head1 INSTANCE VARIABLES
+
+=item version
+
+=item xformat
+
+=item defaultBaseline
+
+=item deltas
+
+=item stdGlyph
+
+=item ctlPoints
+
+=item lookupFormat
+
+=item lookup
+
+=head1 METHODS
+
+=cut
+
+use strict;
+use vars qw(@ISA);
+
+use Font::TTF::AATutils;
+use Font::TTF::Utils;
+require Font::TTF::Table;
+
+ at ISA = qw(Font::TTF::Table);
+
+=head2 $t->read
+
+Reads the table into memory
+
+=cut
+
+sub read
+{
+ my ($self) = @_;
+ my ($dat, $fh);
+
+ $self->SUPER::read or return $self;
+
+ $fh = $self->{' INFILE'};
+ $fh->read($dat, 8);
+ my ($version, $format, $defaultBaseline) = TTF_Unpack("fSS", $dat);
+
+ if ($format == 0 or $format == 1) {
+ $fh->read($dat, 64);
+ $self->{'deltas'} = [TTF_Unpack("s*", $dat)];
+ }
+ elsif ($format == 2 or $format == 3) {
+ $fh->read($dat, 2);
+ $self->{'stdGlyph'} = unpack("n", $dat);
+ $fh->read($dat, 64);
+ $self->{'ctlPoints'} = unpack("n*", $dat);
+ }
+ else {
+ die "unknown table format";
+ }
+
+ if ($format == 1 or $format == 3) {
+ my $len = $self->{' LENGTH'} - ($fh->tell() - $self->{' OFFSET'});
+ my ($lookupFormat, $lookup) = AAT_read_lookup($fh, 2, $len, $defaultBaseline);
+ $self->{'lookupFormat'} = $lookupFormat;
+ $self->{'lookup'} = $lookup;
+ }
+
+ $self->{'version'} = $version;
+ $self->{'format'} = $format;
+ $self->{'defaultBaseline'} = $defaultBaseline;
+
+ $self;
+}
+
+=head2 $t->out($fh)
+
+Writes the table to a file either from memory or by copying
+
+=cut
+
+sub out
+{
+ my ($self, $fh) = @_;
+
+ return $self->SUPER::out($fh) unless $self->{' read'};
+
+ my $format = $self->{'format'};
+ my $defaultBaseline = $self->{'defaultBaseline'};
+ $fh->print(TTF_Pack("fSS", $self->{'version'}, $format, $defaultBaseline));
+
+ AAT_write_lookup($fh, $self->{'lookupFormat'}, $self->{'lookup'}, 2, $defaultBaseline) if ($format == 1 or $format == 3);
+}
+
+=head2 $t->print($fh)
+
+Prints a human-readable representation of the table
+
+=cut
+
+sub print
+{
+ my ($self, $fh) = @_;
+
+ $self->read;
+
+ $fh = 'STDOUT' unless defined $fh;
+
+ my $format = $self->{'format'};
+ $fh->printf("version %f\nformat %d\ndefaultBaseline %d\n", $self->{'version'}, $format, $self->{'defaultBaseline'});
+ if ($format == 0 or $format == 1) {
+ $fh->printf("\tdeltas:\n");
+ my $deltas = $self->{'deltas'};
+ foreach (0 .. 31) {
+ $fh->printf("\t\t%d: %d%s\n", $_, $deltas->[$_], defined baselineName_($_) ? "\t# " . baselineName_($_) : "");
+ }
+ }
+ if ($format == 2 or $format == 3) {
+ $fh->printf("\tstdGlyph = %d\n", $self->{'stdGlyph'});
+ my $ctlPoints = $self->{'ctlPoints'};
+ foreach (0 .. 31) {
+ $fh->printf("\t\t%d: %d%s\n", $_, $ctlPoints->[$_], defined baselineName_($_) ? "\t# " . baselineName_($_) : "");
+ }
+ }
+ if ($format == 1 or $format == 3) {
+ $fh->printf("lookupFormat %d\n", $self->{'lookupFormat'});
+ my $lookup = $self->{'lookup'};
+ foreach (sort { $a <=> $b } keys %$lookup) {
+ $fh->printf("\tglyph %d: %d%s\n", $_, $lookup->{$_}, defined baselineName_($_) ? "\t# " . baselineName_($_) : "");
+ }
+ }
+}
+
+sub baselineName_
+{
+ my ($b) = @_;
+ my @baselines = ( 'Roman', 'Ideographic centered', 'Ideographic low', 'Hanging', 'Math' );
+ $baselines[$b];
+}
+
+1;
+
+
+=head1 BUGS
+
+None known
+
+=head1 AUTHOR
+
+Jonathan Kew L<Jonathan_Kew at sil.org>. See L<Font::TTF::Font> for copyright and
+licensing.
+
+=cut
+
Modified: packages/libfont-ttf-perl/trunk/lib/Font/TTF/Cmap.pm
===================================================================
--- packages/libfont-ttf-perl/trunk/lib/Font/TTF/Cmap.pm 2006-01-17 02:56:43 UTC (rev 1966)
+++ packages/libfont-ttf-perl/trunk/lib/Font/TTF/Cmap.pm 2006-01-17 03:07:20 UTC (rev 1967)
@@ -1,478 +1,495 @@
-package Font::TTF::Cmap;
-
-=head1 NAME
-
-Font::TTF::Cmap - Character map table
-
-=head1 DESCRIPTION
-
-Looks after the character map. For ease of use, the actual cmap is held in
-a hash against codepoint. Thus for a given table:
-
- $gid = $font->{'cmap'}{'Tables'}[0]{'val'}{$code};
-
-Note that C<$code> should be a true value (0x1234) rather than a string representation.
-
-=head1 INSTANCE VARIABLES
-
-The instance variables listed here are not preceeded by a space due to their
-emulating structural information in the font.
-
-=over 4
-
-=item Num
-
-Number of subtables in this table
-
-=item Tables
-
-An array of subtables ([0..Num-1])
-
-=back
-
-Each subtables also has its own instance variables which are, again, not
-preceeded by a space.
-
-=over 4
-
-=item Platform
-
-The platform number for this subtable
-
-=item Encoding
-
-The encoding number for this subtable
-
-=item Format
-
-Gives the stored format of this subtable
-
-=item Ver
-
-Gives the version (or language) information for this subtable
-
-=item val
-
-A hash keyed by the codepoint value (not a string) storing the glyph id
-
-=back
-
-=head1 METHODS
-
-=cut
-
-use strict;
-use vars qw(@ISA);
-use Font::TTF::Table;
-use Font::TTF::Utils;
-
- at ISA = qw(Font::TTF::Table);
-
-
-=head2 $t->read
-
-Reads the cmap into memory. Format 4 subtables read the whole subtable and
-fill in the segmented array accordingly.
-
-Format 2 subtables are not read at all.
-
-=cut
-
-sub read
-{
- my ($self) = @_;
- my ($dat, $i, $j, $k, $id, @ids, $s);
- my ($start, $end, $range, $delta, $form, $len, $num, $ver, $sg);
- my ($fh) = $self->{' INFILE'};
-
- $self->SUPER::read or return $self;
- $fh->read($dat, 4);
- $self->{'Num'} = unpack("x2n", $dat);
- $self->{'Tables'} = [];
- for ($i = 0; $i < $self->{'Num'}; $i++)
- {
- $s = {};
- $fh->read($dat, 8);
- ($s->{'Platform'}, $s->{'Encoding'}, $s->{'LOC'}) = (unpack("nnN", $dat));
- $s->{'LOC'} += $self->{' OFFSET'};
- push(@{$self->{'Tables'}}, $s);
- }
- for ($i = 0; $i < $self->{'Num'}; $i++)
- {
- $s = $self->{'Tables'}[$i];
- $fh->seek($s->{'LOC'}, 0);
- $fh->read($dat, 2);
- $form = unpack("n", $dat);
-
- $s->{'Format'} = $form;
- if ($form == 0)
- {
- my ($j) = 0;
-
- $fh->read($dat, 4);
- ($len, $s->{'Ver'}) = unpack('n2', $dat);
- $fh->read($dat, 256);
- $s->{'val'} = {map {$j++; ($_ ? ($j - 1, $_) : ())} unpack("C*", $dat)};
- } elsif ($form == 6)
- {
- my ($start, $ecount);
-
- $fh->read($dat, 8);
- ($len, $s->{'Ver'}, $start, $ecount) = unpack('n4', $dat);
- $fh->read($dat, $ecount << 1);
- $s->{'val'} = {map {$start++; ($_ ? ($start - 1, $_) : ())} unpack("n*", $dat)};
- } elsif ($form == 2)
- {
-# no idea what to do here yet
- } elsif ($form == 4)
- {
- $fh->read($dat, 12);
- ($len, $s->{'Ver'}, $num) = unpack('n3', $dat);
- $num >>= 1;
- $fh->read($dat, $len - 14);
- for ($j = 0; $j < $num; $j++)
- {
- $end = unpack("n", substr($dat, $j << 1, 2));
- $start = unpack("n", substr($dat, ($j << 1) + ($num << 1) + 2, 2));
- $delta = unpack("n", substr($dat, ($j << 1) + ($num << 2) + 2, 2));
- $delta -= 65536 if $delta > 32767;
- $range = unpack("n", substr($dat, ($j << 1) + $num * 6 + 2, 2));
- for ($k = $start; $k <= $end; $k++)
- {
- if ($range == 0 || $range == 65535) # support the buggy FOG with its range=65535 for final segment
- { $id = $k + $delta; }
- else
- { $id = unpack("n", substr($dat, ($j << 1) + $num * 6 +
- 2 + ($k - $start) * 2 + $range, 2)) + $delta; }
- $id -= 65536 if $id >= 65536;
- $s->{'val'}{$k} = $id if ($id);
- }
- }
- } elsif ($form == 8 || $form == 12)
- {
- $fh->read($dat, 10);
- ($len, $s->{'Ver'}) = unpack('x2N2', $dat);
- if ($form == 8)
- {
- $fh->read($dat, 8196);
- $num = unpack("N", substr($dat, 8192, 4)); # don't need the map
- } else
- {
- $fh->read($dat, 4);
- $num = unpack("N", $dat);
- }
- $fh->read($dat, 12 * $num);
- for ($j = 0; $j < $num; $j++)
- {
- ($start, $end, $sg) = unpack("N3", substr($dat, $j * 12, 12));
- for ($k = $start; $k <= $end; $k++)
- { $s->{'val'}{$k} = $sg++; }
- }
- } elsif ($form == 10)
- {
- $fh->read($dat, 18);
- ($len, $s->{'Ver'}, $start, $num) = unpack('x2N4', $dat);
- $fh->read($dat, $num << 1);
- for ($j = 0; $j < $num; $j++)
- { $s->{'val'}{$start + $j} = unpack("n", substr($dat, $j << 1, 2)); }
- }
- }
- $self;
-}
-
-
-=head2 $t->ms_lookup($uni)
-
-Finds a Unicode table, giving preference to the MS one, and looks up the given
-Unicode codepoint in it to find the glyph id.
-
-=cut
-
-sub ms_lookup
-{
- my ($self, $uni) = @_;
-
- $self->find_ms || return undef unless (defined $self->{' mstable'});
- return $self->{' mstable'}{'val'}{$uni};
-}
-
-
-=head2 $t->find_ms
-
-Finds the a Unicode table, giving preference to the Microsoft one, and sets the C<mstable> instance variable
-to it if found. Returns the table it finds.
-
-=cut
-sub find_ms
-{
- my ($self) = @_;
- my ($i, $s, $alt, $found);
-
- return $self->{' mstable'} if defined $self->{' mstable'};
- $self->read;
- for ($i = 0; $i < $self->{'Num'}; $i++)
- {
- $s = $self->{'Tables'}[$i];
- if ($s->{'Platform'} == 3)
- {
- $self->{' mstable'} = $s;
- last if ($s->{'Encoding'} == 10);
- $found = 1 if ($s->{'Encoding'} == 1);
- } elsif ($s->{'Platform'} == 0 || ($s->{'Platform'} == 2 && $s->{'Encoding'} == 1))
- { $alt = $s; }
- }
- $self->{' mstable'} = $alt if ($alt && !$found);
- $self->{' mstable'};
-}
-
-
-=head2 $t->ms_enc
-
-Returns the encoding of the microsoft table (0 => symbol, etc.). Returns undef if there is
-no Microsoft cmap.
-
-=cut
-
-sub ms_enc
-{
- my ($self) = @_;
- my ($s);
-
- return $self->{' mstable'}{'Encoding'}
- if (defined $self->{' mstable'} && $self->{' mstable'}{'Platform'} == 3);
-
- foreach $s (@{$self->{'Tables'}})
- {
- return $s->{'Encoding'} if ($s->{'Platform'} == 3);
- }
- return undef;
-}
-
-
-=head2 $t->out($fh)
-
-Writes out a cmap table to a filehandle. If it has not been read, then
-just copies from input file to output
-
-=cut
-
-sub out
-{
- my ($self, $fh) = @_;
- my ($loc, $s, $i, $base_loc, $j, @keys);
-
- return $self->SUPER::out($fh) unless $self->{' read'};
-
-
- $self->{'Tables'} = [sort {$a->{'Platform'} <=> $b->{'Platform'}
- || $a->{'Encoding'} <=> $b->{'Encoding'}
- || $a->{'Ver'} <=> $b->{'Ver'}} @{$self->{'Tables'}}];
- $self->{'Num'} = scalar @{$self->{'Tables'}};
-
- $base_loc = $fh->tell();
- $fh->print(pack("n2", 0, $self->{'Num'}));
-
- for ($i = 0; $i < $self->{'Num'}; $i++)
- { $fh->print(pack("nnN", $self->{'Tables'}[$i]{'Platform'}, $self->{'Tables'}[$i]{'Encoding'}, 0)); }
-
- for ($i = 0; $i < $self->{'Num'}; $i++)
- {
- $s = $self->{'Tables'}[$i];
- @keys = sort {$a <=> $b} keys %{$s->{'val'}};
- $s->{' outloc'} = $fh->tell();
- if ($s->{'Format'} < 8)
- { $fh->print(pack("n3", $s->{'Format'}, 0, $s->{'Ver'})); } # come back for length
- else
- { $fh->print(pack("n2N2", $s->{'Format'}, 0, 0, $s->{'Ver'})); }
-
- if ($s->{'Format'} == 0)
- {
- $fh->print(pack("C256", @{$s->{'val'}}{0 .. 255}));
- } elsif ($s->{'Format'} == 6)
- {
- $fh->print(pack("n2", $keys[0], $keys[-1] - $keys[0] + 1));
- $fh->print(pack("n*", @{$s->{'val'}}{$keys[0] .. $keys[-1]}));
- } elsif ($s->{'Format'} == 2)
- {
- } elsif ($s->{'Format'} == 4)
- {
- my ($num, $sRange, $eSel, $eShift, @starts, @ends, $doff);
- my (@deltas, $delta, @range, $flat, $k, $segs, $count, $newseg, $v);
-
- push(@keys, 0xFFFF) unless ($keys[-1] == 0xFFFF);
- $newseg = 1; $num = 0;
- for ($j = 0; $j <= $#keys && $keys[$j] <= 0xFFFF; $j++)
- {
- $v = $s->{'val'}{$keys[$j]};
- if ($newseg)
- {
- $delta = $v;
- $doff = $j;
- $flat = 1;
- push(@starts, $keys[$j]);
- $newseg = 0;
- }
- $delta = 0 if ($delta + $j - $doff != $v);
- $flat = 0 if ($v == 0);
- if ($j == $#keys || $keys[$j] + 1 != $keys[$j+1])
- {
- push (@ends, $keys[$j]);
- push (@deltas, $delta ? $delta - $keys[$doff] : 0);
- push (@range, $flat);
- $num++;
- $newseg = 1;
- }
- }
-
- ($num, $sRange, $eSel, $eShift) = Font::TTF::Utils::TTF_bininfo($num, 2);
- $fh->print(pack("n4", $num * 2, $sRange, $eSel, $eShift));
- $fh->print(pack("n*", @ends));
- $fh->print(pack("n", 0));
- $fh->print(pack("n*", @starts));
- $fh->print(pack("n*", @deltas));
-
- $count = 0;
- for ($j = 0; $j < $num; $j++)
- {
- $delta = $deltas[$j];
- if ($delta != 0 && $range[$j] == 1)
- { $range[$j] = 0; }
- else
- {
- $range[$j] = ($count + $num - $j) << 1;
- $count += $ends[$j] - $starts[$j] + 1;
- }
- }
-
- $fh->print(pack("n*", @range));
-
- for ($j = 0; $j < $num; $j++)
- {
- next if ($range[$j] == 0);
- $fh->print(pack("n*", @{$s->{'val'}}{$starts[$j] .. $ends[$j]}));
- }
- } elsif ($s->{'Format'} == 8 || $s->{'Format'} == 12)
- {
- my (@jobs, $start, $current, $curr_glyf, $map);
-
- $map = "\000" x 8192;
- foreach $j (@keys)
- {
- if ($j > 0xFFFF)
- {
- if (defined $s->{'val'}{$j >> 16})
- { $s->{'Format'} = 12; }
- vec($map, $j >> 16, 1) = 1;
- }
- if ($j != $current + 1 || $s->{'val'}{$j} != $curr_glyf + 1)
- {
- push (@jobs, [$start, $current, $curr_glyf - ($current - $start)]) if (defined $start);
- $start = $j; $current = $j; $curr_glyf = $s->{'val'}{$j};
- }
- $current = $j;
- $curr_glyf = $s->{'val'}{$j};
- }
- push (@jobs, [$start, $current, $curr_glyf - ($current - $start)]) if (defined $start);
- $fh->print($map) if ($s->{'Format'} == 8);
- $fh->print(pack('N', $#jobs + 1));
- foreach $j (@jobs)
- { $fh->print(pack('N3', @{$j})); }
- } elsif ($s->{'Format'} == 10)
- {
- $fh->print(pack('N2', $keys[0], $keys[-1] - $keys[0] + 1));
- $fh->print(pack('n*', $s->{'val'}{$keys[0] .. $keys[-1]}));
- }
-
- $loc = $fh->tell();
- if ($s->{'Format'} < 8)
- {
- $fh->seek($s->{' outloc'} + 2, 0);
- $fh->print(pack("n", $loc - $s->{' outloc'}));
- } else
- {
- $fh->seek($s->{' outloc'} + 4, 0);
- $fh->print(pack("N", $loc - $s->{' outloc'}));
- }
- $fh->seek($base_loc + 8 + ($i << 3), 0);
- $fh->print(pack("N", $s->{' outloc'} - $base_loc));
- $fh->seek($loc, 0);
- }
- $self;
-}
-
-
-=head2 $t->XML_element($context, $depth, $name, $val)
-
-Outputs the elements of the cmap in XML. We only need to process val here
-
-=cut
-
-sub XML_element
-{
- my ($self, $context, $depth, $k, $val) = @_;
- my ($fh) = $context->{'fh'};
- my ($i);
-
- return $self if ($k eq 'LOC');
- return $self->SUPER::XML_element($context, $depth, $k, $val) unless ($k eq 'val');
-
- $fh->print("$depth<mappings>\n");
- foreach $i (sort {$a <=> $b} keys %{$val})
- { $fh->printf("%s<map code='%04X' glyph='%s'/>\n", $depth . $context->{'indent'}, $i, $val->{$i}); }
- $fh->print("$depth</mappings>\n");
- $self;
-}
-
-=head2 @map = $t->reverse([$num])
-
-Returns a reverse map of the table of given number or the Unicode
-cmap. I.e. given a glyph gives the Unicode value for it.
-
-=cut
-
-sub reverse
-{
- my ($self, $tnum) = @_;
- my ($table) = defined $tnum ? $self->{'Tables'}[$tnum] : $self->find_ms;
- my (@res, $code, $gid);
-
- while (($code, $gid) = each(%{$table->{'val'}}))
- { $res[$gid] = $code unless (defined $res[$gid] && $res[$gid] > 0 && $res[$gid] < $code); }
- @res;
-}
-
-
-=head2 is_unicode($index)
-
-Returns whether the table of a given index is known to be a unicode table
-(as specified in the specifications)
-
-=cut
-
-sub is_unicode
-{
- my ($self, $index) = @_;
- my ($pid, $eid) = ($self->{'Tables'}[$index]{'Platform'}, $self->{'Tables'}[$index]{'Encoding'});
-
- return ($pid == 3 || $pid == 0 || ($pid == 2 && $eid == 1));
-}
-
-1;
-
-=head1 BUGS
-
-=over 4
-
-=item *
-
-No support for format 2 tables (MBCS)
-
-=back
-
-=head1 AUTHOR
-
-Martin Hosken Martin_Hosken at sil.org. See L<Font::TTF::Font> for copyright and
-licensing.
-
-=cut
-
+package Font::TTF::Cmap;
+
+=head1 NAME
+
+Font::TTF::Cmap - Character map table
+
+=head1 DESCRIPTION
+
+Looks after the character map. For ease of use, the actual cmap is held in
+a hash against codepoint. Thus for a given table:
+
+ $gid = $font->{'cmap'}{'Tables'}[0]{'val'}{$code};
+
+Note that C<$code> should be a true value (0x1234) rather than a string representation.
+
+=head1 INSTANCE VARIABLES
+
+The instance variables listed here are not preceeded by a space due to their
+emulating structural information in the font.
+
+=over 4
+
+=item Num
+
+Number of subtables in this table
+
+=item Tables
+
+An array of subtables ([0..Num-1])
+
+=back
+
+Each subtables also has its own instance variables which are, again, not
+preceeded by a space.
+
+=over 4
+
+=item Platform
+
+The platform number for this subtable
+
+=item Encoding
+
+The encoding number for this subtable
+
+=item Format
+
+Gives the stored format of this subtable
+
+=item Ver
+
+Gives the version (or language) information for this subtable
+
+=item val
+
+A hash keyed by the codepoint value (not a string) storing the glyph id
+
+=back
+
+=head1 METHODS
+
+=cut
+
+use strict;
+use vars qw(@ISA);
+use Font::TTF::Table;
+use Font::TTF::Utils;
+
+ at ISA = qw(Font::TTF::Table);
+
+
+=head2 $t->read
+
+Reads the cmap into memory. Format 4 subtables read the whole subtable and
+fill in the segmented array accordingly.
+
+Format 2 subtables are not read at all.
+
+=cut
+
+sub read
+{
+ my ($self) = @_;
+ my ($dat, $i, $j, $k, $id, @ids, $s);
+ my ($start, $end, $range, $delta, $form, $len, $num, $ver, $sg);
+ my ($fh) = $self->{' INFILE'};
+
+ $self->SUPER::read or return $self;
+ $fh->read($dat, 4);
+ $self->{'Num'} = unpack("x2n", $dat);
+ $self->{'Tables'} = [];
+ for ($i = 0; $i < $self->{'Num'}; $i++)
+ {
+ $s = {};
+ $fh->read($dat, 8);
+ ($s->{'Platform'}, $s->{'Encoding'}, $s->{'LOC'}) = (unpack("nnN", $dat));
+ $s->{'LOC'} += $self->{' OFFSET'};
+ push(@{$self->{'Tables'}}, $s);
+ }
+ for ($i = 0; $i < $self->{'Num'}; $i++)
+ {
+ $s = $self->{'Tables'}[$i];
+ $fh->seek($s->{'LOC'}, 0);
+ $fh->read($dat, 2);
+ $form = unpack("n", $dat);
+
+ $s->{'Format'} = $form;
+ if ($form == 0)
+ {
+ my ($j) = 0;
+
+ $fh->read($dat, 4);
+ ($len, $s->{'Ver'}) = unpack('n2', $dat);
+ $fh->read($dat, 256);
+ $s->{'val'} = {map {$j++; ($_ ? ($j - 1, $_) : ())} unpack("C*", $dat)};
+ } elsif ($form == 6)
+ {
+ my ($start, $ecount);
+
+ $fh->read($dat, 8);
+ ($len, $s->{'Ver'}, $start, $ecount) = unpack('n4', $dat);
+ $fh->read($dat, $ecount << 1);
+ $s->{'val'} = {map {$start++; ($_ ? ($start - 1, $_) : ())} unpack("n*", $dat)};
+ } elsif ($form == 2)
+ {
+# no idea what to do here yet
+ } elsif ($form == 4)
+ {
+ $fh->read($dat, 12);
+ ($len, $s->{'Ver'}, $num) = unpack('n3', $dat);
+ $num >>= 1;
+ $fh->read($dat, $len - 14);
+ for ($j = 0; $j < $num; $j++)
+ {
+ $end = unpack("n", substr($dat, $j << 1, 2));
+ $start = unpack("n", substr($dat, ($j << 1) + ($num << 1) + 2, 2));
+ $delta = unpack("n", substr($dat, ($j << 1) + ($num << 2) + 2, 2));
+ $delta -= 65536 if $delta > 32767;
+ $range = unpack("n", substr($dat, ($j << 1) + $num * 6 + 2, 2));
+ for ($k = $start; $k <= $end; $k++)
+ {
+ if ($range == 0 || $range == 65535) # support the buggy FOG with its range=65535 for final segment
+ { $id = $k + $delta; }
+ else
+ { $id = unpack("n", substr($dat, ($j << 1) + $num * 6 +
+ 2 + ($k - $start) * 2 + $range, 2)) + $delta; }
+ $id -= 65536 if $id >= 65536;
+ $s->{'val'}{$k} = $id if ($id);
+ }
+ }
+ } elsif ($form == 8 || $form == 12)
+ {
+ $fh->read($dat, 10);
+ ($len, $s->{'Ver'}) = unpack('x2N2', $dat);
+ if ($form == 8)
+ {
+ $fh->read($dat, 8196);
+ $num = unpack("N", substr($dat, 8192, 4)); # don't need the map
+ } else
+ {
+ $fh->read($dat, 4);
+ $num = unpack("N", $dat);
+ }
+ $fh->read($dat, 12 * $num);
+ for ($j = 0; $j < $num; $j++)
+ {
+ ($start, $end, $sg) = unpack("N3", substr($dat, $j * 12, 12));
+ for ($k = $start; $k <= $end; $k++)
+ { $s->{'val'}{$k} = $sg++; }
+ }
+ } elsif ($form == 10)
+ {
+ $fh->read($dat, 18);
+ ($len, $s->{'Ver'}, $start, $num) = unpack('x2N4', $dat);
+ $fh->read($dat, $num << 1);
+ for ($j = 0; $j < $num; $j++)
+ { $s->{'val'}{$start + $j} = unpack("n", substr($dat, $j << 1, 2)); }
+ }
+ }
+ $self;
+}
+
+
+=head2 $t->ms_lookup($uni)
+
+Finds a Unicode table, giving preference to the MS one, and looks up the given
+Unicode codepoint in it to find the glyph id.
+
+=cut
+
+sub ms_lookup
+{
+ my ($self, $uni) = @_;
+
+ $self->find_ms || return undef unless (defined $self->{' mstable'});
+ return $self->{' mstable'}{'val'}{$uni};
+}
+
+
+=head2 $t->find_ms
+
+Finds the a Unicode table, giving preference to the Microsoft one, and sets the C<mstable> instance variable
+to it if found. Returns the table it finds.
+
+=cut
+sub find_ms
+{
+ my ($self) = @_;
+ my ($i, $s, $alt, $found);
+
+ return $self->{' mstable'} if defined $self->{' mstable'};
+ $self->read;
+ for ($i = 0; $i < $self->{'Num'}; $i++)
+ {
+ $s = $self->{'Tables'}[$i];
+ if ($s->{'Platform'} == 3)
+ {
+ $self->{' mstable'} = $s;
+ last if ($s->{'Encoding'} == 10);
+ $found = 1 if ($s->{'Encoding'} == 1);
+ } elsif ($s->{'Platform'} == 0 || ($s->{'Platform'} == 2 && $s->{'Encoding'} == 1))
+ { $alt = $s; }
+ }
+ $self->{' mstable'} = $alt if ($alt && !$found);
+ $self->{' mstable'};
+}
+
+
+=head2 $t->ms_enc
+
+Returns the encoding of the microsoft table (0 => symbol, etc.). Returns undef if there is
+no Microsoft cmap.
+
+=cut
+
+sub ms_enc
+{
+ my ($self) = @_;
+ my ($s);
+
+ return $self->{' mstable'}{'Encoding'}
+ if (defined $self->{' mstable'} && $self->{' mstable'}{'Platform'} == 3);
+
+ foreach $s (@{$self->{'Tables'}})
+ {
+ return $s->{'Encoding'} if ($s->{'Platform'} == 3);
+ }
+ return undef;
+}
+
+
+=head2 $t->out($fh)
+
+Writes out a cmap table to a filehandle. If it has not been read, then
+just copies from input file to output
+
+=cut
+
+sub out
+{
+ my ($self, $fh) = @_;
+ my ($loc, $s, $i, $base_loc, $j, @keys);
+
+ return $self->SUPER::out($fh) unless $self->{' read'};
+
+
+ $self->{'Tables'} = [sort {$a->{'Platform'} <=> $b->{'Platform'}
+ || $a->{'Encoding'} <=> $b->{'Encoding'}
+ || $a->{'Ver'} <=> $b->{'Ver'}} @{$self->{'Tables'}}];
+ $self->{'Num'} = scalar @{$self->{'Tables'}};
+
+ $base_loc = $fh->tell();
+ $fh->print(pack("n2", 0, $self->{'Num'}));
+
+ for ($i = 0; $i < $self->{'Num'}; $i++)
+ { $fh->print(pack("nnN", $self->{'Tables'}[$i]{'Platform'}, $self->{'Tables'}[$i]{'Encoding'}, 0)); }
+
+ for ($i = 0; $i < $self->{'Num'}; $i++)
+ {
+ $s = $self->{'Tables'}[$i];
+ @keys = sort {$a <=> $b} keys %{$s->{'val'}};
+ $s->{' outloc'} = $fh->tell();
+ if ($s->{'Format'} < 8)
+ { $fh->print(pack("n3", $s->{'Format'}, 0, $s->{'Ver'})); } # come back for length
+ else
+ { $fh->print(pack("n2N2", $s->{'Format'}, 0, 0, $s->{'Ver'})); }
+
+ if ($s->{'Format'} == 0)
+ {
+ $fh->print(pack("C256", @{$s->{'val'}}{0 .. 255}));
+ } elsif ($s->{'Format'} == 6)
+ {
+ $fh->print(pack("n2", $keys[0], $keys[-1] - $keys[0] + 1));
+ $fh->print(pack("n*", @{$s->{'val'}}{$keys[0] .. $keys[-1]}));
+ } elsif ($s->{'Format'} == 2)
+ {
+ } elsif ($s->{'Format'} == 4)
+ {
+ my ($num, $sRange, $eSel, $eShift, @starts, @ends, $doff);
+ my (@deltas, $delta, @range, $flat, $k, $segs, $count, $newseg, $v);
+
+ push(@keys, 0xFFFF) unless ($keys[-1] == 0xFFFF);
+ $newseg = 1; $num = 0;
+ for ($j = 0; $j <= $#keys && $keys[$j] <= 0xFFFF; $j++)
+ {
+ $v = $s->{'val'}{$keys[$j]};
+ if ($newseg)
+ {
+ $delta = $v;
+ $doff = $j;
+ $flat = 1;
+ push(@starts, $keys[$j]);
+ $newseg = 0;
+ }
+ $delta = 0 if ($delta + $j - $doff != $v);
+ $flat = 0 if ($v == 0);
+ if ($j == $#keys || $keys[$j] + 1 != $keys[$j+1])
+ {
+ push (@ends, $keys[$j]);
+ push (@deltas, $delta ? $delta - $keys[$doff] : 0);
+ push (@range, $flat);
+ $num++;
+ $newseg = 1;
+ }
+ }
+
+ ($num, $sRange, $eSel, $eShift) = Font::TTF::Utils::TTF_bininfo($num, 2);
+ $fh->print(pack("n4", $num * 2, $sRange, $eSel, $eShift));
+ $fh->print(pack("n*", @ends));
+ $fh->print(pack("n", 0));
+ $fh->print(pack("n*", @starts));
+ $fh->print(pack("n*", @deltas));
+
+ $count = 0;
+ for ($j = 0; $j < $num; $j++)
+ {
+ $delta = $deltas[$j];
+ if ($delta != 0 && $range[$j] == 1)
+ { $range[$j] = 0; }
+ else
+ {
+ $range[$j] = ($count + $num - $j) << 1;
+ $count += $ends[$j] - $starts[$j] + 1;
+ }
+ }
+
+ $fh->print(pack("n*", @range));
+
+ for ($j = 0; $j < $num; $j++)
+ {
+ next if ($range[$j] == 0);
+ $fh->print(pack("n*", @{$s->{'val'}}{$starts[$j] .. $ends[$j]}));
+ }
+ } elsif ($s->{'Format'} == 8 || $s->{'Format'} == 12)
+ {
+ my (@jobs, $start, $current, $curr_glyf, $map);
+
+ $map = "\000" x 8192;
+ foreach $j (@keys)
+ {
+ if ($j > 0xFFFF)
+ {
+ if (defined $s->{'val'}{$j >> 16})
+ { $s->{'Format'} = 12; }
+ vec($map, $j >> 16, 1) = 1;
+ }
+ if ($j != $current + 1 || $s->{'val'}{$j} != $curr_glyf + 1)
+ {
+ push (@jobs, [$start, $current, $curr_glyf - ($current - $start)]) if (defined $start);
+ $start = $j; $current = $j; $curr_glyf = $s->{'val'}{$j};
+ }
+ $current = $j;
+ $curr_glyf = $s->{'val'}{$j};
+ }
+ push (@jobs, [$start, $current, $curr_glyf - ($current - $start)]) if (defined $start);
+ $fh->print($map) if ($s->{'Format'} == 8);
+ $fh->print(pack('N', $#jobs + 1));
+ foreach $j (@jobs)
+ { $fh->print(pack('N3', @{$j})); }
+ } elsif ($s->{'Format'} == 10)
+ {
+ $fh->print(pack('N2', $keys[0], $keys[-1] - $keys[0] + 1));
+ $fh->print(pack('n*', $s->{'val'}{$keys[0] .. $keys[-1]}));
+ }
+
+ $loc = $fh->tell();
+ if ($s->{'Format'} < 8)
+ {
+ $fh->seek($s->{' outloc'} + 2, 0);
+ $fh->print(pack("n", $loc - $s->{' outloc'}));
+ } else
+ {
+ $fh->seek($s->{' outloc'} + 4, 0);
+ $fh->print(pack("N", $loc - $s->{' outloc'}));
+ }
+ $fh->seek($base_loc + 8 + ($i << 3), 0);
+ $fh->print(pack("N", $s->{' outloc'} - $base_loc));
+ $fh->seek($loc, 0);
+ }
+ $self;
+}
+
+
+=head2 $t->XML_element($context, $depth, $name, $val)
+
+Outputs the elements of the cmap in XML. We only need to process val here
+
+=cut
+
+sub XML_element
+{
+ my ($self, $context, $depth, $k, $val) = @_;
+ my ($fh) = $context->{'fh'};
+ my ($i);
+
+ return $self if ($k eq 'LOC');
+ return $self->SUPER::XML_element($context, $depth, $k, $val) unless ($k eq 'val');
+
+ $fh->print("$depth<mappings>\n");
+ foreach $i (sort {$a <=> $b} keys %{$val})
+ { $fh->printf("%s<map code='%04X' glyph='%s'/>\n", $depth . $context->{'indent'}, $i, $val->{$i}); }
+ $fh->print("$depth</mappings>\n");
+ $self;
+}
+
+=head2 @map = $t->reverse(%opt)
+
+Returns a reverse map of the Unicode cmap. I.e. given a glyph gives the Unicode value for it. Options are:
+
+=over 4
+
+=item tnum
+
+Table number to use rather than the default Unicode table
+
+=item array
+
+Returns each element of reverse as an array since a glyph may be mapped by more
+than one Unicode value. The arrays are unsorted.
+
+=back
+
+=cut
+
+sub reverse
+{
+ my ($self, %opt) = @_;
+ my ($table) = defined $opt{'tnum'} ? $self->{'Tables'}[$opt{'tnum'}] : $self->find_ms;
+ my (@res, $code, $gid);
+
+ while (($code, $gid) = each(%{$table->{'val'}}))
+ {
+ if ($opt{'array'})
+ { push (@{$res[$gid]}, $code); }
+ else
+ { $res[$gid] = $code unless (defined $res[$gid] && $res[$gid] > 0 && $res[$gid] < $code); }
+ }
+ @res;
+}
+
+
+=head2 is_unicode($index)
+
+Returns whether the table of a given index is known to be a unicode table
+(as specified in the specifications)
+
+=cut
+
+sub is_unicode
+{
+ my ($self, $index) = @_;
+ my ($pid, $eid) = ($self->{'Tables'}[$index]{'Platform'}, $self->{'Tables'}[$index]{'Encoding'});
+
+ return ($pid == 3 || $pid == 0 || ($pid == 2 && $eid == 1));
+}
+
+1;
+
+=head1 BUGS
+
+=over 4
+
+=item *
+
+No support for format 2 tables (MBCS)
+
+=back
+
+=head1 AUTHOR
+
+Martin Hosken Martin_Hosken at sil.org. See L<Font::TTF::Font> for copyright and
+licensing.
+
+=cut
+
Modified: packages/libfont-ttf-perl/trunk/lib/Font/TTF/Coverage.pm
===================================================================
--- packages/libfont-ttf-perl/trunk/lib/Font/TTF/Coverage.pm 2006-01-17 02:56:43 UTC (rev 1966)
+++ packages/libfont-ttf-perl/trunk/lib/Font/TTF/Coverage.pm 2006-01-17 03:07:20 UTC (rev 1967)
@@ -1,253 +1,253 @@
-package Font::TTF::Coverage;
-
-=head1 NAME
-
-Font::TTF::Coverage - Opentype coverage and class definition objects
-
-=head1 DESCRIPTION
-
-Coverage tables and class definition objects are virtually identical concepts
-in OpenType. Their difference comes purely in their storage. Therefore we can
-say that a coverage table is a class definition in which the class definition
-for each glyph is the corresponding index in the coverage table. The resulting
-data structure is that a Coverage table has the following fields:
-
-=item cover
-
-A boolean to indicate whether this table is a coverage table (TRUE) or a
-class definition (FALSE)
-
-=item val
-
-A hash of glyph ids against values (either coverage index or class value)
-
-=item fmt
-
-The storage format used is given here, but is recalculated when the table
-is written out.
-
-=item count
-
-A count of the elements in a coverage table for use with add. Each subsequent
-addition is added with the current count and increments the count.
-
-=head1 METHODS
-
-=cut
-
-=head2 new($isCover [, vals])
-
-Creates a new coverage table or class definition table, depending upon the
-value of $isCover. if $isCover then vals may be a list of glyphs to include in order.
-If no $isCover, then vals is a hash of glyphs against class values.
-
-=cut
-
-sub new
-{
- my ($class) = shift;
- my ($isCover) = shift;
- my ($self) = {};
-
- $self->{'cover'} = $isCover;
- $self->{'count'} = 0;
- if ($isCover)
- {
- my ($v);
- foreach $v (@_)
- { $self->{'val'}{$v} = $self->{'count'}++; }
- }
- else
- { $self->{'val'} = {@_}; }
- bless $self, $class;
-}
-
-
-=head2 read($fh)
-
-Reads the coverage/class table from the given file handle
-
-=cut
-
-sub read
-{
- my ($self, $fh) = @_;
- my ($dat, $fmt, $num, $i, $c);
-
- $fh->read($dat, 4);
- ($fmt, $num) = unpack("n2", $dat);
- $self->{'fmt'} = $fmt;
-
- if ($self->{'cover'})
- {
- if ($fmt == 1)
- {
- $fh->read($dat, $num << 1);
- map {$self->{'val'}{$_} = $i++} unpack("n*", $dat);
- } elsif ($fmt == 2)
- {
- $fh->read($dat, $num * 6);
- for ($i = 0; $i < $num; $i++)
- {
- ($first, $last, $c) = unpack("n3", substr($dat, $i * 6, 6));
- map {$self->{'val'}{$_} = $c++} ($first .. $last);
- }
- }
- } elsif ($fmt == 1)
- {
- $fh->read($dat, 2);
- $first = $num;
- ($num) = unpack("n", $dat);
- $fh->read($dat, $num << 1);
- map {$self->{'val'}{$first++} = $_} unpack("n*", $dat);
- } elsif ($fmt == 2)
- {
- $fh->read($dat, $num * 6);
- for ($i = 0; $i < $num; $i++)
- {
- ($first, $last, $c) = unpack("n3", substr($dat, $i * 6, 6));
- map {$self->{'val'}{$_} = $c} ($first .. $last);
- }
- }
- $self;
-}
-
-
-=head2 out($fh, $state)
-
-Writes the coverage/class table to the given file handle. If $state is 1 then
-the output string is returned rather than being output to a filehandle.
-
-=cut
-
-sub out
-{
- my ($self, $fh, $state) = @_;
- my ($g, $eff, $grp, $out);
- my ($shipout) = ($state ? sub {$out .= $_[0];} : sub {$fh->print($_[0]);});
- my (@gids) = sort {$a <=> $b} keys %{$self->{'val'}};
-
- $fmt = 1; $grp = 1;
- for ($i = 1; $i <= $#gids; $i++)
- {
- if ($self->{'val'}{$gids[$i]} < $self->{'val'}{$gids[$i-1]} && $self->{'cover'})
- {
- $fmt = 2;
- last;
- } elsif ($gids[$i] == $gids[$i-1] + 1)
- { $eff++; }
- else
- { $grp++; }
- }
- if ($self->{'cover'})
- { $fmt = 2 if ($eff / $grp > 4); }
- else
- { $fmt = 2 if ($grp > 1); }
-
- if ($fmt == 1 && $self->{'cover'})
- {
- my ($last) = 0;
- &$shipout(pack('n2', 1, scalar @gids));
- &$shipout(pack('n*', @gids));
- } elsif ($fmt == 1)
- {
- my ($last) = $gids[0];
- &$shipout(pack("n3", 1, $last, $gids[-1] - $last + 1));
- foreach $g (@gids)
- {
- if ($g > $last + 1)
- { &$shipout(pack('n*', 0 x ($g - $last - 1))); }
- &$shipout(pack('n', $self->{'val'}{$g}));
- $last = $g;
- }
- } else
- {
- my ($start, $end, $ind, $numloc, $endloc, $num);
- &$shipout(pack("n2", 2, 0));
- $numloc = $fh->tell() - 2 unless $state;
-
- $start = 0; $end = 0; $num = 0;
- while ($end < $#gids)
- {
- if ($gids[$end + 1] == $gids[$end] + 1
- && $self->{'val'}{$gids[$end + 1]}
- == $self->{'val'}{$gids[$end]}
- + ($self->{'cover'} ? 1 : 0))
- {
- $end++;
- next;
- }
-
- &$shipout(pack("n3", $gids[$start], $gids[$end],
- $self->{'val'}{$gids[$start]}));
- $start = $end + 1;
- $end++;
- $num++;
- }
- &$shipout(pack("n3", $gids[$start], $gids[$end],
- $self->{'val'}{$gids[$start]}));
- $num++;
- if ($state)
- { substr($out, 2, 2) = pack('n', $num); }
- else
- {
- $endloc = $fh->tell();
- $fh->seek($numloc, 0);
- $fh->print(pack("n", $num));
- $fh->seek($endloc, 0);
- }
- }
- return ($state ? $out : $self);
-}
-
-
-=head2 $c->add($glyphid)
-
-Adds a glyph id to the coverage table incrementing the count so that each subsequent addition
-has the next sequential number. Returns the index number of the glyphid added
-
-=cut
-
-sub add
-{
- my ($self, $gid) = @_;
-
- return $self->{'val'}{$gid} if (defined $self->{'val'}{$gid});
- $self->{'val'}{$gid} = $self->{'count'};
- return $self->{'count'}++;
-}
-
-
-=head2 $c->out_xml($context)
-
-Outputs this coverage/class in XML
-
-=cut
-
-sub out_xml
-{
- my ($self, $context, $depth) = @_;
- my ($fh) = $context->{'fh'};
-
- $fh->print("$depth<" . ($self->{'cover'} ? 'coverage' : 'class') . ">\n");
- foreach $gid (sort {$a <=> $b} keys %{$self->{'val'}})
- {
- $fh->printf("$depth$context->{'indent'}<gref glyph='%s' val='%s'/>\n", $gid, $self->{'val'}{$gid});
- }
- $fh->print("$depth</" . ($self->{'cover'} ? 'coverage' : 'class') . ">\n");
- $self;
-}
-
-sub release
-{ }
-
-
-=head1 AUTHOR
-
-Martin Hosken Martin_Hosken at sil.org. See L<Font::TTF::Font> for copyright and
-licensing.
-
-=cut
-
-1;
-
+package Font::TTF::Coverage;
+
+=head1 TITLE
+
+Font::TTF::Coverage - Opentype coverage and class definition objects
+
+=head1 DESCRIPTION
+
+Coverage tables and class definition objects are virtually identical concepts
+in OpenType. Their difference comes purely in their storage. Therefore we can
+say that a coverage table is a class definition in which the class definition
+for each glyph is the corresponding index in the coverage table. The resulting
+data structure is that a Coverage table has the following fields:
+
+=item cover
+
+A boolean to indicate whether this table is a coverage table (TRUE) or a
+class definition (FALSE)
+
+=item val
+
+A hash of glyph ids against values (either coverage index or class value)
+
+=item fmt
+
+The storage format used is given here, but is recalculated when the table
+is written out.
+
+=item count
+
+A count of the elements in a coverage table for use with add. Each subsequent
+addition is added with the current count and increments the count.
+
+=head1 METHODS
+
+=cut
+
+=head2 new($isCover [, vals])
+
+Creates a new coverage table or class definition table, depending upon the
+value of $isCover. if $isCover then vals may be a list of glyphs to include in order.
+If no $isCover, then vals is a hash of glyphs against class values.
+
+=cut
+
+sub new
+{
+ my ($class) = shift;
+ my ($isCover) = shift;
+ my ($self) = {};
+
+ $self->{'cover'} = $isCover;
+ $self->{'count'} = 0;
+ if ($isCover)
+ {
+ my ($v);
+ foreach $v (@_)
+ { $self->{'val'}{$v} = $self->{'count'}++; }
+ }
+ else
+ { $self->{'val'} = {@_}; }
+ bless $self, $class;
+}
+
+
+=head2 read($fh)
+
+Reads the coverage/class table from the given file handle
+
+=cut
+
+sub read
+{
+ my ($self, $fh) = @_;
+ my ($dat, $fmt, $num, $i, $c);
+
+ $fh->read($dat, 4);
+ ($fmt, $num) = unpack("n2", $dat);
+ $self->{'fmt'} = $fmt;
+
+ if ($self->{'cover'})
+ {
+ if ($fmt == 1)
+ {
+ $fh->read($dat, $num << 1);
+ map {$self->{'val'}{$_} = $i++} unpack("n*", $dat);
+ } elsif ($fmt == 2)
+ {
+ $fh->read($dat, $num * 6);
+ for ($i = 0; $i < $num; $i++)
+ {
+ ($first, $last, $c) = unpack("n3", substr($dat, $i * 6, 6));
+ map {$self->{'val'}{$_} = $c++} ($first .. $last);
+ }
+ }
+ } elsif ($fmt == 1)
+ {
+ $fh->read($dat, 2);
+ $first = $num;
+ ($num) = unpack("n", $dat);
+ $fh->read($dat, $num << 1);
+ map {$self->{'val'}{$first++} = $_} unpack("n*", $dat);
+ } elsif ($fmt == 2)
+ {
+ $fh->read($dat, $num * 6);
+ for ($i = 0; $i < $num; $i++)
+ {
+ ($first, $last, $c) = unpack("n3", substr($dat, $i * 6, 6));
+ map {$self->{'val'}{$_} = $c} ($first .. $last);
+ }
+ }
+ $self;
+}
+
+
+=head2 out($fh, $state)
+
+Writes the coverage/class table to the given file handle. If $state is 1 then
+the output string is returned rather than being output to a filehandle.
+
+=cut
+
+sub out
+{
+ my ($self, $fh, $state) = @_;
+ my ($g, $eff, $grp, $out);
+ my ($shipout) = ($state ? sub {$out .= $_[0];} : sub {$fh->print($_[0]);});
+ my (@gids) = sort {$a <=> $b} keys %{$self->{'val'}};
+
+ $fmt = 1; $grp = 1;
+ for ($i = 1; $i <= $#gids; $i++)
+ {
+ if ($self->{'val'}{$gids[$i]} < $self->{'val'}{$gids[$i-1]} && $self->{'cover'})
+ {
+ $fmt = 2;
+ last;
+ } elsif ($gids[$i] == $gids[$i-1] + 1)
+ { $eff++; }
+ else
+ { $grp++; }
+ }
+ if ($self->{'cover'})
+ { $fmt = 2 if ($eff / $grp > 4); }
+ else
+ { $fmt = 2 if ($grp > 1); }
+
+ if ($fmt == 1 && $self->{'cover'})
+ {
+ my ($last) = 0;
+ &$shipout(pack('n2', 1, scalar @gids));
+ &$shipout(pack('n*', @gids));
+ } elsif ($fmt == 1)
+ {
+ my ($last) = $gids[0];
+ &$shipout(pack("n3", 1, $last, $gids[-1] - $last + 1));
+ foreach $g (@gids)
+ {
+ if ($g > $last + 1)
+ { &$shipout(pack('n*', 0 x ($g - $last - 1))); }
+ &$shipout(pack('n', $self->{'val'}{$g}));
+ $last = $g;
+ }
+ } else
+ {
+ my ($start, $end, $ind, $numloc, $endloc, $num);
+ &$shipout(pack("n2", 2, 0));
+ $numloc = $fh->tell() - 2 unless $state;
+
+ $start = 0; $end = 0; $num = 0;
+ while ($end < $#gids)
+ {
+ if ($gids[$end + 1] == $gids[$end] + 1
+ && $self->{'val'}{$gids[$end + 1]}
+ == $self->{'val'}{$gids[$end]}
+ + ($self->{'cover'} ? 1 : 0))
+ {
+ $end++;
+ next;
+ }
+
+ &$shipout(pack("n3", $gids[$start], $gids[$end],
+ $self->{'val'}{$gids[$start]}));
+ $start = $end + 1;
+ $end++;
+ $num++;
+ }
+ &$shipout(pack("n3", $gids[$start], $gids[$end],
+ $self->{'val'}{$gids[$start]}));
+ $num++;
+ if ($state)
+ { substr($out, 2, 2) = pack('n', $num); }
+ else
+ {
+ $endloc = $fh->tell();
+ $fh->seek($numloc, 0);
+ $fh->print(pack("n", $num));
+ $fh->seek($endloc, 0);
+ }
+ }
+ return ($state ? $out : $self);
+}
+
+
+=head2 $c->add($glyphid)
+
+Adds a glyph id to the coverage table incrementing the count so that each subsequent addition
+has the next sequential number. Returns the index number of the glyphid added
+
+=cut
+
+sub add
+{
+ my ($self, $gid) = @_;
+
+ return $self->{'val'}{$gid} if (defined $self->{'val'}{$gid});
+ $self->{'val'}{$gid} = $self->{'count'};
+ return $self->{'count'}++;
+}
+
+
+=head2 $c->out_xml($context)
+
+Outputs this coverage/class in XML
+
+=cut
+
+sub out_xml
+{
+ my ($self, $context, $depth) = @_;
+ my ($fh) = $context->{'fh'};
+
+ $fh->print("$depth<" . ($self->{'cover'} ? 'coverage' : 'class') . ">\n");
+ foreach $gid (sort {$a <=> $b} keys %{$self->{'val'}})
+ {
+ $fh->printf("$depth$context->{'indent'}<gref glyph='%s' val='%s'/>\n", $gid, $self->{'val'}{$gid});
+ }
+ $fh->print("$depth</" . ($self->{'cover'} ? 'coverage' : 'class') . ">\n");
+ $self;
+}
+
+sub release
+{ }
+
+
+=head1 AUTHOR
+
+Martin Hosken Martin_Hosken at sil.org. See L<Font::TTF::Font> for copyright and
+licensing.
+
+=cut
+
+1;
+
Modified: packages/libfont-ttf-perl/trunk/lib/Font/TTF/Cvt_.pm
===================================================================
--- packages/libfont-ttf-perl/trunk/lib/Font/TTF/Cvt_.pm 2006-01-17 02:56:43 UTC (rev 1966)
+++ packages/libfont-ttf-perl/trunk/lib/Font/TTF/Cvt_.pm 2006-01-17 03:07:20 UTC (rev 1967)
@@ -1,81 +1,81 @@
-package Font::TTF::Cvt_;
-
-=head1 NAME
-
-Font::TTF::Cvt_ - Control Value Table in a TrueType font
-
-=head1 DESCRIPTION
-
-This is a minimal class adding nothing beyond a table, but is a repository
-for cvt type information for those processes brave enough to address hinting.
-
-=head1 INSTANCE VARIABLES
-
-=over 4
-
-=item val
-
-This is an array of CVT values. Thus access to the CVT is via:
-
- $f->{'cvt_'}{'val'}[$num];
-
-=back
-
-=head1 METHODS
-
-=cut
-
-use strict;
-use vars qw(@ISA $VERSION);
-use Font::TTF::Utils;
-
- at ISA = qw(Font::TTF::Table);
-
-$VERSION = 0.0001;
-
-=head2 $t->read
-
-Reads the CVT table into both the tables C<' dat'> variable and the C<val>
-array.
-
-=cut
-
-sub read
-{
- my ($self) = @_;
-
- $self->read_dat || return undef;
- $self->{' read'} = 1;
- $self->{'val'} = [TTF_Unpack("s*", $self->{' dat'})];
- $self;
-}
-
-
-=head2 $t->update
-
-Updates the RAM file copy C<' dat'> to be the same as the array.
-
-=cut
-
-sub update
-{
- my ($self) = @_;
-
- return undef unless ($self->{' read'} && $#{$self->{'val'}} >= 0);
- $self->{' dat'} = TTF_Pack("s*", @{$self->{'val'}});
- $self;
-}
-
-1;
-
-=head1 BUGS
-
-None known
-
-=head1 AUTHOR
-
-Martin Hosken Martin_Hosken at sil.org. See L<Font::TTF::Font> for copyright and
-licensing.
-
-=cut
-
+package Font::TTF::Cvt_;
+
+=head1 NAME
+
+Font::TTF::Cvt_ - Control Value Table in a TrueType font
+
+=head1 DESCRIPTION
+
+This is a minimal class adding nothing beyond a table, but is a repository
+for cvt type information for those processes brave enough to address hinting.
+
+=head1 INSTANCE VARIABLES
+
+=over 4
+
+=item val
+
+This is an array of CVT values. Thus access to the CVT is via:
+
+ $f->{'cvt_'}{'val'}[$num];
+
+=back
+
+=head1 METHODS
+
+=cut
+
+use strict;
+use vars qw(@ISA $VERSION);
+use Font::TTF::Utils;
+
+ at ISA = qw(Font::TTF::Table);
+
+$VERSION = 0.0001;
+
+=head2 $t->read
+
+Reads the CVT table into both the tables C<' dat'> variable and the C<val>
+array.
+
+=cut
+
+sub read
+{
+ my ($self) = @_;
+
+ $self->read_dat || return undef;
+ $self->{' read'} = 1;
+ $self->{'val'} = [TTF_Unpack("s*", $self->{' dat'})];
+ $self;
+}
+
+
+=head2 $t->update
+
+Updates the RAM file copy C<' dat'> to be the same as the array.
+
+=cut
+
+sub update
+{
+ my ($self) = @_;
+
+ return undef unless ($self->{' read'} && $#{$self->{'val'}} >= 0);
+ $self->{' dat'} = TTF_Pack("s*", @{$self->{'val'}});
+ $self;
+}
+
+1;
+
+=head1 BUGS
+
+None known
+
+=head1 AUTHOR
+
+Martin Hosken Martin_Hosken at sil.org. See L<Font::TTF::Font> for copyright and
+licensing.
+
+=cut
+
Modified: packages/libfont-ttf-perl/trunk/lib/Font/TTF/Delta.pm
===================================================================
--- packages/libfont-ttf-perl/trunk/lib/Font/TTF/Delta.pm 2006-01-17 02:56:43 UTC (rev 1966)
+++ packages/libfont-ttf-perl/trunk/lib/Font/TTF/Delta.pm 2006-01-17 03:07:20 UTC (rev 1967)
@@ -1,160 +1,160 @@
-package Font::TTF::Delta;
-
-=head1 NAME
-
-SIL::TTF::Delta - Opentype Device tables
-
-=head1 DESCRIPTION
-
-Each device table corresponds to a set of deltas for a particular point over
-a range of ppem values.
-
-=item first
-
-The first ppem value in the range
-
-=item last
-
-The last ppem value in the range
-
-=item val
-
-This is an array of deltas corresponding to each ppem in the range between
-first and last inclusive.
-
-=item fmt
-
-This is the fmt used (log2 of number bits per value) when the device table was
-read. It is recalculated on output.
-
-=head1 METHODS
-
-=cut
-
-use strict;
-use Font::TTF::Utils;
-
-=head2 new
-
-Creates a new device table
-
-=cut
-
-sub new
-{
- my ($class) = @_;
- my ($self) = {};
-
- bless $self, $class;
-}
-
-
-=head2 read
-
-Reads a device table from the given IO object at the current location
-
-=cut
-
-sub read
-{
- my ($self, $fh) = @_;
- my ($dat, $fmt, $num, $i, $j, $mask);
-
- $fh->read($dat, 6);
- ($self->{'first'}, $self->{'last'}, $fmt) = TTF_Unpack("S3", $dat);
- $self->{'fmt'} = $fmt;
-
- $fmt = 1 << $fmt;
- $num = ((($self->{'last'} - $self->{'first'} + 1) * $fmt) + 15) >> 8;
- $fh->read($dat, $num);
-
- $mask = (0xffff << (16 - $fmt)) & 0xffff;
- $j = 0;
- for ($i = $self->{'first'}; $i <= $self->{'last'}; $i++)
- {
- if ($j == 0)
- {
- $num = TTF_Unpack("S", substr($dat, 0, 2));
- substr($dat, 0, 2) = '';
- }
- push (@{$self->{'val'}}, ($num & $mask) >> (16 - $fmt));
- $num <<= $fmt;
- $j += $fmt;
- $j = 0 if ($j >= 16);
- }
- $self;
-}
-
-
-=head2 out($fh, $style)
-
-Outputs a device table to the given IO object at the current location, or just
-returns the data to be output if $style != 0
-
-=cut
-
-sub out
-{
- my ($self, $fh, $style) = @_;
- my ($dat, $fmt, $num, $mask, $j, $f, $out);
-
- foreach $f (@{$self->{'val'}})
- {
- my ($tfmt) = $f > 0 ? $f + 1 : -$f;
- $fmt = $tfmt if $tfmt > $fmt;
- }
-
- if ($fmt > 8)
- { $fmt = 3; }
- elsif ($fmt > 2)
- { $fmt = 2; }
- else
- { $fmt = 1; }
-
- $out = TTF_Pack("S3", $self->{'first'}, $self->{'last'}, $fmt);
-
- $fmt = 1 << $fmt;
- $mask = 0xffff >> (16 - $fmt);
- $j = 0; $dat = 0;
- foreach $f (@{$self->{'val'}})
- {
- $dat |= ($f & $mask) << (16 - $fmt - $j);
- $j += $fmt;
- if ($j >= 16)
- {
- $j = 0;
- $out .= TTF_Pack("S", $dat);
- $dat = 0;
- }
- }
- $out .= pack('n', $dat) if ($j > 0);
- $fh->print($out) unless $style;
- $out;
-}
-
-
-=head2 $d->out_xml($context)
-
-Outputs a delta in XML
-
-=cut
-
-sub out_xml
-{
- my ($self, $context, $depth) = @_;
- my ($fh) = $context->{'fh'};
-
- $fh->printf("%s<delta first='%s' last='%s'>\n", $depth, $self->{'first'}, $self->{'last'});
- $fh->print("$depth$context->{'indent'}" . join (' ', @{$self->{'val'}}) . "\n") if defined ($self->{'val'});
- $fh->print("$depth</delta>\n");
-}
-
-=head1 AUTHOR
-
-Martin Hosken Martin_Hosken at sil.org. See L<Font::TTF::Font> for copyright and
-licensing.
-
-=cut
-
-1;
-
+package Font::TTF::Delta;
+
+=head1 TITLE
+
+Font::TTF::Delta - Opentype Device tables
+
+=head1 DESCRIPTION
+
+Each device table corresponds to a set of deltas for a particular point over
+a range of ppem values.
+
+=item first
+
+The first ppem value in the range
+
+=item last
+
+The last ppem value in the range
+
+=item val
+
+This is an array of deltas corresponding to each ppem in the range between
+first and last inclusive.
+
+=item fmt
+
+This is the fmt used (log2 of number bits per value) when the device table was
+read. It is recalculated on output.
+
+=head1 METHODS
+
+=cut
+
+use strict;
+use Font::TTF::Utils;
+
+=head2 new
+
+Creates a new device table
+
+=cut
+
+sub new
+{
+ my ($class) = @_;
+ my ($self) = {};
+
+ bless $self, $class;
+}
+
+
+=head2 read
+
+Reads a device table from the given IO object at the current location
+
+=cut
+
+sub read
+{
+ my ($self, $fh) = @_;
+ my ($dat, $fmt, $num, $i, $j, $mask);
+
+ $fh->read($dat, 6);
+ ($self->{'first'}, $self->{'last'}, $fmt) = TTF_Unpack("S3", $dat);
+ $self->{'fmt'} = $fmt;
+
+ $fmt = 1 << $fmt;
+ $num = ((($self->{'last'} - $self->{'first'} + 1) * $fmt) + 15) >> 8;
+ $fh->read($dat, $num);
+
+ $mask = (0xffff << (16 - $fmt)) & 0xffff;
+ $j = 0;
+ for ($i = $self->{'first'}; $i <= $self->{'last'}; $i++)
+ {
+ if ($j == 0)
+ {
+ $num = TTF_Unpack("S", substr($dat, 0, 2));
+ substr($dat, 0, 2) = '';
+ }
+ push (@{$self->{'val'}}, ($num & $mask) >> (16 - $fmt));
+ $num <<= $fmt;
+ $j += $fmt;
+ $j = 0 if ($j >= 16);
+ }
+ $self;
+}
+
+
+=head2 out($fh, $style)
+
+Outputs a device table to the given IO object at the current location, or just
+returns the data to be output if $style != 0
+
+=cut
+
+sub out
+{
+ my ($self, $fh, $style) = @_;
+ my ($dat, $fmt, $num, $mask, $j, $f, $out);
+
+ foreach $f (@{$self->{'val'}})
+ {
+ my ($tfmt) = $f > 0 ? $f + 1 : -$f;
+ $fmt = $tfmt if $tfmt > $fmt;
+ }
+
+ if ($fmt > 8)
+ { $fmt = 3; }
+ elsif ($fmt > 2)
+ { $fmt = 2; }
+ else
+ { $fmt = 1; }
+
+ $out = TTF_Pack("S3", $self->{'first'}, $self->{'last'}, $fmt);
+
+ $fmt = 1 << $fmt;
+ $mask = 0xffff >> (16 - $fmt);
+ $j = 0; $dat = 0;
+ foreach $f (@{$self->{'val'}})
+ {
+ $dat |= ($f & $mask) << (16 - $fmt - $j);
+ $j += $fmt;
+ if ($j >= 16)
+ {
+ $j = 0;
+ $out .= TTF_Pack("S", $dat);
+ $dat = 0;
+ }
+ }
+ $out .= pack('n', $dat) if ($j > 0);
+ $fh->print($out) unless $style;
+ $out;
+}
+
+
+=head2 $d->out_xml($context)
+
+Outputs a delta in XML
+
+=cut
+
+sub out_xml
+{
+ my ($self, $context, $depth) = @_;
+ my ($fh) = $context->{'fh'};
+
+ $fh->printf("%s<delta first='%s' last='%s'>\n", $depth, $self->{'first'}, $self->{'last'});
+ $fh->print("$depth$context->{'indent'}" . join (' ', @{$self->{'val'}}) . "\n") if defined ($self->{'val'});
+ $fh->print("$depth</delta>\n");
+}
+
+=head1 AUTHOR
+
+Martin Hosken Martin_Hosken at sil.org. See L<Font::TTF::Font> for copyright and
+licensing.
+
+=cut
+
+1;
+
Modified: packages/libfont-ttf-perl/trunk/lib/Font/TTF/Fdsc.pm
===================================================================
--- packages/libfont-ttf-perl/trunk/lib/Font/TTF/Fdsc.pm 2006-01-17 02:56:43 UTC (rev 1966)
+++ packages/libfont-ttf-perl/trunk/lib/Font/TTF/Fdsc.pm 2006-01-17 03:07:20 UTC (rev 1967)
@@ -1,125 +1,125 @@
-package Font::TTF::Fdsc;
-
-=head1 NAME
-
-Font::TTF::Fdsc - Font Descriptors table in a font
-
-=head1 DESCRIPTION
-
-=head1 INSTANCE VARIABLES
-
-=item version
-
-=item descriptors
-
-Hash keyed by descriptor tags
-
-=head1 METHODS
-
-=cut
-
-use strict;
-use vars qw(@ISA %fields);
-use Font::TTF::Utils;
-
- at ISA = qw(Font::TTF::Table);
-
-=head2 $t->read
-
-Reads the table into memory
-
-=cut
-
-sub read
-{
- my ($self) = @_;
- my ($dat, $fh, $numDescs, $tag, $descs);
-
- $self->SUPER::read or return $self;
-
- $fh = $self->{' INFILE'};
- $fh->read($dat, 4);
- $self->{'version'} = TTF_Unpack("f", $dat);
-
- $fh->read($dat, 4);
-
- foreach (1 .. unpack("N", $dat)) {
- $fh->read($tag, 4);
- $fh->read($dat, 4);
- $descs->{$tag} = ($tag eq 'nalf') ? unpack("N", $dat) : TTF_Unpack("f", $dat);
- }
-
- $self->{'descriptors'} = $descs;
-
- $self;
-}
-
-
-=head2 $t->out($fh)
-
-Writes the table to a file either from memory or by copying
-
-=cut
-
-sub out
-{
- my ($self, $fh) = @_;
- my ($descs);
-
- return $self->SUPER::out($fh) unless $self->{' read'};
-
- $fh->print(TTF_Pack("f", $self->{'version'}));
-
- $descs = $self->{'descriptors'} or {};
-
- $fh->print(pack("N", scalar keys %$descs));
- foreach (sort keys %$descs) {
- $fh->print($_);
- $fh->print(($_ eq 'nalf') ? pack("N", $descs->{$_}) : TTF_Pack("f", $descs->{$_}));
- }
-
- $self;
-}
-
-=head2 $t->print($fh)
-
-Prints a human-readable representation of the table
-
-=cut
-
-sub print
-{
- my ($self, $fh) = @_;
- my ($descs, $k);
-
- $self->read;
-
- $fh = 'STDOUT' unless defined $fh;
-
- $descs = $self->{'descriptors'};
- foreach $k (sort keys %$descs) {
- if ($k eq 'nalf') {
- $fh->printf("Descriptor '%s' = %d\n", $k, $descs->{$k});
- }
- else {
- $fh->printf("Descriptor '%s' = %f\n", $k, $descs->{$k});
- }
- }
-
- $self;
-}
-
-1;
-
-
-=head1 BUGS
-
-None known
-
-=head1 AUTHOR
-
-Jonathan Kew L<Jonathan_Kew at sil.org>. See L<Font::TTF::Font> for copyright and
-licensing.
-
-=cut
-
+package Font::TTF::Fdsc;
+
+=head1 NAME
+
+Font::TTF::Fdsc - Font Descriptors table in a font
+
+=head1 DESCRIPTION
+
+=head1 INSTANCE VARIABLES
+
+=item version
+
+=item descriptors
+
+Hash keyed by descriptor tags
+
+=head1 METHODS
+
+=cut
+
+use strict;
+use vars qw(@ISA %fields);
+use Font::TTF::Utils;
+
+ at ISA = qw(Font::TTF::Table);
+
+=head2 $t->read
+
+Reads the table into memory
+
+=cut
+
+sub read
+{
+ my ($self) = @_;
+ my ($dat, $fh, $numDescs, $tag, $descs);
+
+ $self->SUPER::read or return $self;
+
+ $fh = $self->{' INFILE'};
+ $fh->read($dat, 4);
+ $self->{'version'} = TTF_Unpack("f", $dat);
+
+ $fh->read($dat, 4);
+
+ foreach (1 .. unpack("N", $dat)) {
+ $fh->read($tag, 4);
+ $fh->read($dat, 4);
+ $descs->{$tag} = ($tag eq 'nalf') ? unpack("N", $dat) : TTF_Unpack("f", $dat);
+ }
+
+ $self->{'descriptors'} = $descs;
+
+ $self;
+}
+
+
+=head2 $t->out($fh)
+
+Writes the table to a file either from memory or by copying
+
+=cut
+
+sub out
+{
+ my ($self, $fh) = @_;
+ my ($descs);
+
+ return $self->SUPER::out($fh) unless $self->{' read'};
+
+ $fh->print(TTF_Pack("f", $self->{'version'}));
+
+ $descs = $self->{'descriptors'} or {};
+
+ $fh->print(pack("N", scalar keys %$descs));
+ foreach (sort keys %$descs) {
+ $fh->print($_);
+ $fh->print(($_ eq 'nalf') ? pack("N", $descs->{$_}) : TTF_Pack("f", $descs->{$_}));
+ }
+
+ $self;
+}
+
+=head2 $t->print($fh)
+
+Prints a human-readable representation of the table
+
+=cut
+
+sub print
+{
+ my ($self, $fh) = @_;
+ my ($descs, $k);
+
+ $self->read;
+
+ $fh = 'STDOUT' unless defined $fh;
+
+ $descs = $self->{'descriptors'};
+ foreach $k (sort keys %$descs) {
+ if ($k eq 'nalf') {
+ $fh->printf("Descriptor '%s' = %d\n", $k, $descs->{$k});
+ }
+ else {
+ $fh->printf("Descriptor '%s' = %f\n", $k, $descs->{$k});
+ }
+ }
+
+ $self;
+}
+
+1;
+
+
+=head1 BUGS
+
+None known
+
+=head1 AUTHOR
+
+Jonathan Kew L<Jonathan_Kew at sil.org>. See L<Font::TTF::Font> for copyright and
+licensing.
+
+=cut
+
Modified: packages/libfont-ttf-perl/trunk/lib/Font/TTF/Feat.pm
===================================================================
--- packages/libfont-ttf-perl/trunk/lib/Font/TTF/Feat.pm 2006-01-17 02:56:43 UTC (rev 1966)
+++ packages/libfont-ttf-perl/trunk/lib/Font/TTF/Feat.pm 2006-01-17 03:07:20 UTC (rev 1967)
@@ -1,191 +1,191 @@
-package Font::TTF::Feat;
-
-=head1 NAME
-
-Font::TTF::Feat - Font Features
-
-=head1 DESCRIPTION
-
-=head1 INSTANCE VARIABLES
-
-=over 4
-
-=item version
-
-=item features
-
-An array of hashes of the following form
-
-=over 8
-
-=item feature
-
-feature id number
-
-=item name
-
-name index in name table
-
-=item exclusive
-
-exclusive flag
-
-=item settings
-
-hash of setting number against name string index
-
-=back
-
-=back
-
-=head1 METHODS
-
-=cut
-
-use strict;
-use vars qw(@ISA);
-
-use Font::TTF::Utils;
-
-require Font::TTF::Table;
-
- at ISA = qw(Font::TTF::Table);
-
-=head2 $t->read
-
-Reads the features from the TTF file into memory
-
-=cut
-
-sub read
-{
- my ($self) = @_;
- my ($featureCount, $features);
-
- $self->SUPER::read_dat or return $self;
-
- ($self->{'version'}, $featureCount) = TTF_Unpack("fS", $self->{' dat'});
-
- $features = [];
- foreach (1 .. $featureCount) {
- my ($feature, $nSettings, $settingTable, $featureFlags, $nameIndex)
- = TTF_Unpack("SSLSS", substr($self->{' dat'}, $_ * 12, 12));
- push @$features,
- {
- 'feature' => $feature,
- 'name' => $nameIndex,
- 'exclusive' => (($featureFlags & 0x8000) != 0),
- 'settings' => { TTF_Unpack("S*", substr($self->{' dat'}, $settingTable, $nSettings * 4)) }
- };
- }
- $self->{'features'} = $features;
-
- delete $self->{' dat'}; # no longer needed, and may become obsolete
-
- $self;
-}
-
-=head2 $t->out($fh)
-
-Writes the features to a TTF file
-
-=cut
-
-sub out
-{
- my ($self, $fh) = @_;
- my ($features, $numFeatures, $settings, $featuresData, $settingsData);
-
- return $self->SUPER::out($fh) unless $self->{' read'};
-
- $features = $self->{'features'};
- $numFeatures = @$features;
-
- foreach (@$features) {
- $settings = $_->{'settings'};
- $featuresData .= TTF_Pack("SSLSS",
- $_->{'feature'},
- scalar keys %$settings,
- 12 + 12 * $numFeatures + length $settingsData,
- ($_->{'exclusive'} ? 0x8000 : 0x0000),
- $_->{'name'});
- foreach (sort {$a <=> $b} keys %$settings) {
- $settingsData .= TTF_Pack("SS", $_, $settings->{$_});
- }
- }
-
- $fh->print(TTF_Pack("fSSL", $self->{'version'}, $numFeatures, 0, 0));
- $fh->print($featuresData);
- $fh->print($settingsData);
-
- $self;
-}
-
-=head2 $t->print($fh)
-
-Prints a human-readable representation of the table
-
-=cut
-
-sub print
-{
- my ($self, $fh) = @_;
- my ($names, $features, $settings);
-
- $self->read;
-
- $names = $self->{' PARENT'}->{'name'};
- $names->read;
-
- $fh = 'STDOUT' unless defined $fh;
-
- $features = $self->{'features'};
- foreach (@$features) {
- $fh->printf("Feature %d, %s, name %d # '%s'\n",
- $_->{'feature'},
- ($_->{'exclusive'} ? "exclusive" : "additive"),
- $_->{'name'},
- $names->{'strings'}[$_->{'name'}][1][0]{0});
- $settings = $_->{'settings'};
- foreach (sort { $a <=> $b } keys %$settings) {
- $fh->printf("\tSetting %d, name %d # '%s'\n",
- $_, $settings->{$_}, $names->{'strings'}[$settings->{$_}][1][0]{0});
- }
- }
-
- $self;
-}
-
-sub settingName
-{
- my ($self, $feature, $setting) = @_;
-
- $self->read;
-
- my $names = $self->{' PARENT'}->{'name'};
- $names->read;
-
- my $features = $self->{'features'};
- my ($featureEntry) = grep { $_->{'feature'} == $feature } @$features;
- my $featureName = $names->{'strings'}[$featureEntry->{'name'}][1][0]{0};
- my $settingName = $featureEntry->{'exclusive'}
- ? $names->{'strings'}[$featureEntry->{'settings'}->{$setting}][1][0]{0}
- : $names->{'strings'}[$featureEntry->{'settings'}->{$setting & ~1}][1][0]{0}
- . (($setting & 1) == 0 ? " On" : " Off");
-
- ($featureName, $settingName);
-}
-
-1;
-
-=head1 BUGS
-
-None known
-
-=head1 AUTHOR
-
-Jonathan Kew L<Jonathan_Kew at sil.org>. See L<Font::TTF::Font> for copyright and
-licensing.
-
-=cut
-
+package Font::TTF::Feat;
+
+=head1 NAME
+
+Font::TTF::Feat - Font Features
+
+=head1 DESCRIPTION
+
+=head1 INSTANCE VARIABLES
+
+=over 4
+
+=item version
+
+=item features
+
+An array of hashes of the following form
+
+=over 8
+
+=item feature
+
+feature id number
+
+=item name
+
+name index in name table
+
+=item exclusive
+
+exclusive flag
+
+=item settings
+
+hash of setting number against name string index
+
+=back
+
+=back
+
+=head1 METHODS
+
+=cut
+
+use strict;
+use vars qw(@ISA);
+
+use Font::TTF::Utils;
+
+require Font::TTF::Table;
+
+ at ISA = qw(Font::TTF::Table);
+
+=head2 $t->read
+
+Reads the features from the TTF file into memory
+
+=cut
+
+sub read
+{
+ my ($self) = @_;
+ my ($featureCount, $features);
+
+ $self->SUPER::read_dat or return $self;
+
+ ($self->{'version'}, $featureCount) = TTF_Unpack("fS", $self->{' dat'});
+
+ $features = [];
+ foreach (1 .. $featureCount) {
+ my ($feature, $nSettings, $settingTable, $featureFlags, $nameIndex)
+ = TTF_Unpack("SSLSS", substr($self->{' dat'}, $_ * 12, 12));
+ push @$features,
+ {
+ 'feature' => $feature,
+ 'name' => $nameIndex,
+ 'exclusive' => (($featureFlags & 0x8000) != 0),
+ 'settings' => { TTF_Unpack("S*", substr($self->{' dat'}, $settingTable, $nSettings * 4)) }
+ };
+ }
+ $self->{'features'} = $features;
+
+ delete $self->{' dat'}; # no longer needed, and may become obsolete
+
+ $self;
+}
+
+=head2 $t->out($fh)
+
+Writes the features to a TTF file
+
+=cut
+
+sub out
+{
+ my ($self, $fh) = @_;
+ my ($features, $numFeatures, $settings, $featuresData, $settingsData);
+
+ return $self->SUPER::out($fh) unless $self->{' read'};
+
+ $features = $self->{'features'};
+ $numFeatures = @$features;
+
+ foreach (@$features) {
+ $settings = $_->{'settings'};
+ $featuresData .= TTF_Pack("SSLSS",
+ $_->{'feature'},
+ scalar keys %$settings,
+ 12 + 12 * $numFeatures + length $settingsData,
+ ($_->{'exclusive'} ? 0x8000 : 0x0000),
+ $_->{'name'});
+ foreach (sort {$a <=> $b} keys %$settings) {
+ $settingsData .= TTF_Pack("SS", $_, $settings->{$_});
+ }
+ }
+
+ $fh->print(TTF_Pack("fSSL", $self->{'version'}, $numFeatures, 0, 0));
+ $fh->print($featuresData);
+ $fh->print($settingsData);
+
+ $self;
+}
+
+=head2 $t->print($fh)
+
+Prints a human-readable representation of the table
+
+=cut
+
+sub print
+{
+ my ($self, $fh) = @_;
+ my ($names, $features, $settings);
+
+ $self->read;
+
+ $names = $self->{' PARENT'}->{'name'};
+ $names->read;
+
+ $fh = 'STDOUT' unless defined $fh;
+
+ $features = $self->{'features'};
+ foreach (@$features) {
+ $fh->printf("Feature %d, %s, name %d # '%s'\n",
+ $_->{'feature'},
+ ($_->{'exclusive'} ? "exclusive" : "additive"),
+ $_->{'name'},
+ $names->{'strings'}[$_->{'name'}][1][0]{0});
+ $settings = $_->{'settings'};
+ foreach (sort { $a <=> $b } keys %$settings) {
+ $fh->printf("\tSetting %d, name %d # '%s'\n",
+ $_, $settings->{$_}, $names->{'strings'}[$settings->{$_}][1][0]{0});
+ }
+ }
+
+ $self;
+}
+
+sub settingName
+{
+ my ($self, $feature, $setting) = @_;
+
+ $self->read;
+
+ my $names = $self->{' PARENT'}->{'name'};
+ $names->read;
+
+ my $features = $self->{'features'};
+ my ($featureEntry) = grep { $_->{'feature'} == $feature } @$features;
+ my $featureName = $names->{'strings'}[$featureEntry->{'name'}][1][0]{0};
+ my $settingName = $featureEntry->{'exclusive'}
+ ? $names->{'strings'}[$featureEntry->{'settings'}->{$setting}][1][0]{0}
+ : $names->{'strings'}[$featureEntry->{'settings'}->{$setting & ~1}][1][0]{0}
+ . (($setting & 1) == 0 ? " On" : " Off");
+
+ ($featureName, $settingName);
+}
+
+1;
+
+=head1 BUGS
+
+None known
+
+=head1 AUTHOR
+
+Jonathan Kew L<Jonathan_Kew at sil.org>. See L<Font::TTF::Font> for copyright and
+licensing.
+
+=cut
+
Modified: packages/libfont-ttf-perl/trunk/lib/Font/TTF/Fmtx.pm
===================================================================
--- packages/libfont-ttf-perl/trunk/lib/Font/TTF/Fmtx.pm 2006-01-17 02:56:43 UTC (rev 1966)
+++ packages/libfont-ttf-perl/trunk/lib/Font/TTF/Fmtx.pm 2006-01-17 03:07:20 UTC (rev 1967)
@@ -1,108 +1,108 @@
-package Font::TTF::Fmtx;
-
-=head1 NAME
-
-Font::TTF::Fmtx - Font Metrics table
-
-=head1 DESCRIPTION
-
-This is a simple table with just standards specified instance variables
-
-=head1 INSTANCE VARIABLES
-
- version
- glyphIndex
- horizontalBefore
- horizontalAfter
- horizontalCaretHead
- horizontalCaretBase
- verticalBefore
- verticalAfter
- verticalCaretHead
- verticalCaretBase
-
-=head1 METHODS
-
-=cut
-
-use strict;
-use vars qw(@ISA %fields @field_info);
-
-require Font::TTF::Table;
-use Font::TTF::Utils;
-
- at ISA = qw(Font::TTF::Table);
- at field_info = (
- 'version' => 'f',
- 'glyphIndex' => 'L',
- 'horizontalBefore' => 'c',
- 'horizontalAfter' => 'c',
- 'horizontalCaretHead' => 'c',
- 'horizontalCaretBase' => 'c',
- 'verticalBefore' => 'c',
- 'verticalAfter' => 'c',
- 'verticalCaretHead' => 'c',
- 'verticalCaretBase' => 'c');
-
-sub init
-{
- my ($k, $v, $c, $i);
- for ($i = 0; $i < $#field_info; $i += 2)
- {
- ($k, $v, $c) = TTF_Init_Fields($field_info[$i], $c, $field_info[$i + 1]);
- next unless defined $k && $k ne "";
- $fields{$k} = $v;
- }
-}
-
-
-=head2 $t->read
-
-Reads the table into memory as instance variables
-
-=cut
-
-sub read
-{
- my ($self) = @_;
- my ($dat);
-
- $self->SUPER::read or return $self;
- init unless defined $fields{'glyphIndex'};
- $self->{' INFILE'}->read($dat, 16);
-
- TTF_Read_Fields($self, $dat, \%fields);
- $self;
-}
-
-
-=head2 $t->out($fh)
-
-Writes the table to a file either from memory or by copying.
-
-=cut
-
-sub out
-{
- my ($self, $fh) = @_;
-
- return $self->SUPER::out($fh) unless $self->{' read'};
-
- $fh->print(TTF_Out_Fields($self, \%fields, 16));
- $self;
-}
-
-
-1;
-
-
-=head1 BUGS
-
-None known
-
-=head1 AUTHOR
-
-Jonathan Kew L<Jonathan_Kew at sil.org>. See L<Font::TTF::Font> for copyright and
-licensing.
-
-=cut
+package Font::TTF::Fmtx;
+
+=head1 NAME
+
+Font::TTF::Fmtx - Font Metrics table
+
+=head1 DESCRIPTION
+
+This is a simple table with just standards specified instance variables
+
+=head1 INSTANCE VARIABLES
+
+ version
+ glyphIndex
+ horizontalBefore
+ horizontalAfter
+ horizontalCaretHead
+ horizontalCaretBase
+ verticalBefore
+ verticalAfter
+ verticalCaretHead
+ verticalCaretBase
+
+=head1 METHODS
+
+=cut
+
+use strict;
+use vars qw(@ISA %fields @field_info);
+
+require Font::TTF::Table;
+use Font::TTF::Utils;
+
+ at ISA = qw(Font::TTF::Table);
+ at field_info = (
+ 'version' => 'f',
+ 'glyphIndex' => 'L',
+ 'horizontalBefore' => 'c',
+ 'horizontalAfter' => 'c',
+ 'horizontalCaretHead' => 'c',
+ 'horizontalCaretBase' => 'c',
+ 'verticalBefore' => 'c',
+ 'verticalAfter' => 'c',
+ 'verticalCaretHead' => 'c',
+ 'verticalCaretBase' => 'c');
+
+sub init
+{
+ my ($k, $v, $c, $i);
+ for ($i = 0; $i < $#field_info; $i += 2)
+ {
+ ($k, $v, $c) = TTF_Init_Fields($field_info[$i], $c, $field_info[$i + 1]);
+ next unless defined $k && $k ne "";
+ $fields{$k} = $v;
+ }
+}
+
+
+=head2 $t->read
+
+Reads the table into memory as instance variables
+
+=cut
+
+sub read
+{
+ my ($self) = @_;
+ my ($dat);
+
+ $self->SUPER::read or return $self;
+ init unless defined $fields{'glyphIndex'};
+ $self->{' INFILE'}->read($dat, 16);
+
+ TTF_Read_Fields($self, $dat, \%fields);
+ $self;
+}
+
+
+=head2 $t->out($fh)
+
+Writes the table to a file either from memory or by copying.
+
+=cut
+
+sub out
+{
+ my ($self, $fh) = @_;
+
+ return $self->SUPER::out($fh) unless $self->{' read'};
+
+ $fh->print(TTF_Out_Fields($self, \%fields, 16));
+ $self;
+}
+
+
+1;
+
+
+=head1 BUGS
+
+None known
+
+=head1 AUTHOR
+
+Jonathan Kew L<Jonathan_Kew at sil.org>. See L<Font::TTF::Font> for copyright and
+licensing.
+
+=cut
Modified: packages/libfont-ttf-perl/trunk/lib/Font/TTF/Font.pm
===================================================================
--- packages/libfont-ttf-perl/trunk/lib/Font/TTF/Font.pm 2006-01-17 02:56:43 UTC (rev 1966)
+++ packages/libfont-ttf-perl/trunk/lib/Font/TTF/Font.pm 2006-01-17 03:07:20 UTC (rev 1967)
@@ -1,748 +1,750 @@
-package Font::TTF::Font;
-
-=head1 NAME
-
-Font::TTF::Font - Memory representation of a font
-
-=head1 SYNOPSIS
-
-Here is the regression test (you provide your own font). Run it once and then
-again on the output of the first run. There should be no differences between
-the outputs of the two runs.
-
- $f = Font::TTF::Font->open($ARGV[0]);
-
- # force a read of all the tables
- $f->tables_do(sub { $_[0]->read; });
-
- # force read of all glyphs (use read_dat to use lots of memory!)
- # $f->{'loca'}->glyphs_do(sub { $_[0]->read; });
- $f->{'loca'}->glyphs_do(sub { $_[0]->read_dat; });
- # NB. no need to $g->update since $f->{'glyf'}->out will do it for us
-
- $f->out($ARGV[1]);
- $f->release; # clear up memory forcefully!
-
-=head1 DESCRIPTION
-
-A Truetype font consists of a header containing a directory of tables which
-constitute the rest of the file. This class holds that header and directory and
-also creates objects of the appropriate type for each table within the font.
-Note that it does not read each table into memory, but creates a short reference
-which can be read using the form:
-
- $f->{$tablename}->read;
-
-Classes are included that support many of the different TrueType tables. For
-those for which no special code exists, the table type C<table> is used, which
-defaults to L<Font::TTF::Table>. The current tables which are supported are:
-
- table Font::TTF::Table - for unknown tables
- GDEF Font::TTF::GDEF
- GPOS Font::TTF::GPOS
- GSUB Font::TTF::GSUB
- LTSH Font::TTF::LTSH
- OS/2 Font::TTF::OS_2
- PCLT Font::TTF::PCLT
- bsln Font::TTF::Bsln
- cmap Font::TTF::Cmap - see also Font::TTF::OldCmap
- cvt Font::TTF::Cvt_
- fdsc Font::TTF::Fdsc
- feat Font::TTF::Feat
- fmtx Font::TTF::Fmtx
- fpgm Font::TTF::Fpgm
- glyf Font::TTF::Glyf - see also Font::TTF::Glyph
- hdmx Font::TTF::Hdmx
- head Font::TTF::Head
- hhea Font::TTF::Hhea
- hmtx Font::TTF::Hmtx
- kern Font::TTF::Kern - see alternative Font::TTF::AATKern
- loca Font::TTF::Loca
- maxp Font::TTF::Maxp
- mort Font::TTF::Mort - see also Font::TTF::OldMort
- name Font::TTF::Name
- post Font::TTF::Post
- prep Font::TTF::Prep
- prop Font::TTF::Prop
- vhea Font::TTF::Vhea
- vmtx Font::TTF::Vmtx
-
-Links are:
-
-L<Font::TTF::Table> L<Font::TTF::GDEF> L<Font::TTF::GPOS> L<Font::TTF::GSUB> L<Font::TTF::LTSH>
-L<Font::TTF::OS_2> L<Font::TTF::PCLT> L<Font::TTF::Bsln> L<Font::TTF::Cmap> L<Font::TTF::Cvt_>
-L<Font::TTF::Fdsc> L<Font::TTF::Feat> L<Font::TTF::Fmtx> L<Font::TTF::Fpgm> L<Font::TTF::Glyf>
-L<Font::TTF::Hdmx> L<Font::TTF::Head> L<Font::TTF::Hhea> L<Font::TTF::Hmtx> L<Font::TTF::Kern>
-L<Font::TTF::Loca> L<Font::TTF::Maxp> L<Font::TTF::Mort> L<Font::TTF::Name> L<Font::TTF::Post>
-L<Font::TTF::Prep> L<Font::TTF::Prop> L<Font::TTF::Vhea> L<Font::TTF::Vmtx> L<Font::TTF::OldCmap>
-L<Font::TTF::Glyph> L<Font::TTF::AATKern> L<Font::TTF::OldMort>
-
-
-=head1 INSTANCE VARIABLES
-
-Instance variables begin with a space (and have lengths greater than the 4
-characters which make up table names).
-
-=over
-
-=item nocsum
-
-This is used during output to disable the creation of the file checksum in the
-head table. For example, during DSIG table creation, this flag will be set to
-ensure that the file checksum is left at zero.
-
-=item fname (R)
-
-Contains the filename of the font which this object was read from.
-
-=item INFILE (P)
-
-The file handle which reflects the source file for this font.
-
-=item OFFSET (P)
-
-Contains the offset from the beginning of the read file of this particular
-font directory, thus providing support for TrueType Collections.
-
-=back
-
-=head1 METHODS
-
-=cut
-
-use IO::File;
-
-use strict;
-use vars qw(%tables $VERSION $dumper);
-use Symbol();
-
-require 5.004;
-
-$VERSION = 0.35; # MJPH 4-MAY-2004 Various fixes to OpenType stuff, separate off scripts
-# $VERSION = 0.34; # MJPH 22-MAY-2003 Update PSNames to latest AGL
-# $VERSION = 0.33; # MJPH 9-OCT-2002 Support CFF OpenType (just by version=='OTTO'?!)
-# $VERSION = 0.32; # MJPH 2-OCT-2002 Bug fixes to TTFBuilder, new methods and some
-# extension table support in Ttopen and Coverage
-# $VERSION = 0.31; # MJPH 1-JUL-2002 fix read format 12 cmap (bart at cs.pdx.edu)
-# improve surrogate support in ttfremap
-# fix return warn to return warn,undef
-# ensure correct indexToLocFormat
-# $VERSION = 0.30; # MJPH 28-MAY-2002 add updated release
-# $VERSION = 0.29; # MJPH 9-APR-2002 update ttfbuilder, sort out surrogates
-# $VERSION = 0.28; # MJPH 13-MAR-2002 update ttfbuilder, add Font::TTF::Cmap::ms_enc()
-# $VERSION = 0.27; # MJPH 6-FEB-2002 update ttfbuilder, support no fpgm, no more __DATA__
-# $VERSION = 0.26; # MJPH 19-SEP-2001 Update ttfbuilder
-# $VERSION = 0.25; # MJPH 18-SEP-2001 problems in update of head
-# $VERSION = 0.24; # MJPH 1-AUG-2001 Sort out update
-# $VERSION = 0.23; # GST 30-MAY-2001 Memory leak fixed
-# $VERSION = 0.22; # MJPH 09-APR-2001 Ensure all of AAT stuff included
-# $VERSION = 0.21; # MJPH 23-MAR-2001 Improve Opentype support
-# $VERSION = 0.20; # MJPH 13-JAN-2001 Add XML output and some of XML input, AAT & OT tables
-# $VERSION = 0.19; # MJPH 29-SEP-2000 Add cmap::is_unicode, debug makefile.pl
-# $VERSION = 0.18; # MJPH 21-JUL-2000 Debug Utils::TTF_bininfo
-# $VERSION = 0.17; # MJPH 16-JUN-2000 Add utf8 support to names
-# $VERSION = 0.16; # MJPH 26-APR-2000 Mark read tables as read, tidy up POD
-# $VERSION = 0.15; # MJPH 5-FEB-2000 Ensure right versions released
-# $VERSION = 0.14; # MJPH 11-SEP-1999 Sort out Unixisms, agian!
-# $VERSION = 0.13; # MJPH 9-SEP-1999 Add empty, debug update_bbox
-# $VERSION = 0.12; # MJPH 22-JUL-1999 Add update_bbox
-# $VERSION = 0.11; # MJPH 7-JUL-1999 Don't store empties in cmaps
-# $VERSION = 0.10; # MJPH 21-JUN-1999 Use IO::File
-# $VERSION = 0.09; # MJPH 9-JUN-1999 Add 5.004 require, minor tweeks in cmap
-# $VERSION = 0.08; # MJPH 19-MAY-1999 Sort out line endings for Unix
-# $VERSION = 0.07; # MJPH 28-APR-1999 Get the regression tests to work
-# $VERSION = 0.06; # MJPH 26-APR-1999 Start to add to CVS, correct MANIFEST.SKIP
-# $VERSION = 0.05; # MJPH 13-APR-1999 See changes for 0.05
-# $VERSION = 0.04; # MJPH 13-MAR-1999 Tidy up Tarball
-# $VERSION = 0.03; # MJPH 9-MAR-1999 Move to Font::TTF for CPAN
-# $VERSION = 0.02; # MJPH 12-FEB-1999 Add support for ' nocsum' for DSIGS
-# $VERSION = 0.0001;
-
-%tables = (
- 'table' => 'Font::TTF::Table',
- 'GDEF' => 'Font::TTF::GDEF',
- 'GPOS' => 'Font::TTF::GPOS',
- 'GSUB' => 'Font::TTF::GSUB',
- 'LTSH' => 'Font::TTF::LTSH',
- 'OS/2' => 'Font::TTF::OS_2',
- 'PCLT' => 'Font::TTF::PCLT',
- 'bsln' => 'Font::TTF::Bsln',
- 'cmap' => 'Font::TTF::Cmap',
- 'cvt ' => 'Font::TTF::Cvt_',
- 'fdsc' => 'Font::TTF::Fdsc',
- 'feat' => 'Font::TTF::Feat',
- 'fmtx' => 'Font::TTF::Fmtx',
- 'fpgm' => 'Font::TTF::Fpgm',
- 'glyf' => 'Font::TTF::Glyf',
- 'hdmx' => 'Font::TTF::Hdmx',
- 'head' => 'Font::TTF::Head',
- 'hhea' => 'Font::TTF::Hhea',
- 'hmtx' => 'Font::TTF::Hmtx',
- 'kern' => 'Font::TTF::Kern',
- 'loca' => 'Font::TTF::Loca',
- 'maxp' => 'Font::TTF::Maxp',
- 'mort' => 'Font::TTF::Mort',
- 'name' => 'Font::TTF::Name',
- 'post' => 'Font::TTF::Post',
- 'prep' => 'Font::TTF::Prep',
- 'prop' => 'Font::TTF::Prop',
- 'vhea' => 'Font::TTF::Vhea',
- 'vmtx' => 'Font::TTF::Vmtx',
- );
-
-# This is special code because I am fed up of every time I x a table in the debugger
-# I get the whole font printed. Thus substitutes my 3 line change to dumpvar into
-# the debugger. Clunky, but nice. You are welcome to a copy if you want one.
-
-BEGIN {
- my ($p);
-
- foreach $p (@INC)
- {
- if (-f "$p/mydumpvar.pl")
- {
- $dumper = 'mydumpvar.pl';
- last;
- }
- }
- $dumper ||= 'dumpvar.pl';
-}
-
-sub main::dumpValue
-{ do $dumper; &main::dumpValue; }
-
-
-=head2 Font::TTF::Font->AddTable($tablename, $class)
-
-Adds the given class to be used when representing the given table name. It also
-'requires' the class for you.
-
-=cut
-
-sub AddTable
-{
- my ($class, $table, $useclass) = @_;
-
- $tables{$table} = $useclass;
-# $useclass =~ s|::|/|oig;
-# require "$useclass.pm";
-}
-
-
-=head2 Font::TTF::Font->Init
-
-For those people who like making fonts without reading them. This subroutine
-will require all the table code for the various table types for you. Not
-needed if using Font::TTF::Font::read before using a table.
-
-=cut
-
-sub Init
-{
- my ($class) = @_;
- my ($t);
-
- foreach $t (keys %tables)
- {
- $t =~ s|::|/|oig;
- require "$t.pm";
- }
-}
-
-=head2 Font::TTF::Font->new(%props)
-
-Creates a new font object and initialises with the given properties. This is
-primarily for use when a TTF is embedded somewhere. Notice that the properties
-are automatically preceded by a space when inserted into the object. This is in
-order that fields do not clash with tables.
-
-=cut
-
-sub new
-{
- my ($class, %props) = @_;
- my ($self) = {};
-
- bless $self, $class;
-
- foreach (keys %props)
- { $self->{" $_"} = $props{$_}; }
- $self;
-}
-
-
-=head2 Font::TTF::Font->open($fname)
-
-Reads the header and directory for the given font file and creates appropriate
-objects for each table in the font.
-
-=cut
-
-sub open
-{
- my ($class, $fname) = @_;
- my ($fh);
- my ($self) = {};
-
- unless (ref($fname))
- {
- $fh = IO::File->new($fname) or return undef;
- binmode $fh;
- } else
- { $fh = $fname; }
-
- $self->{' INFILE'} = $fh;
- $self->{' fname'} = $fname;
- $self->{' OFFSET'} = 0;
- bless $self, $class;
-
- $self->read;
-}
-
-=head2 $f->read
-
-Reads a Truetype font directory starting from the current location in the file.
-This has been separated from the C<open> function to allow support for embedded
-TTFs for example in TTCs. Also reads the C<head> and C<maxp> tables immediately.
-
-=cut
-
-sub read
-{
- my ($self) = @_;
- my ($fh) = $self->{' INFILE'};
- my ($dat, $i, $ver, $dir_num, $type, $name, $check, $off, $len, $t);
-
- $fh->seek($self->{' OFFSET'}, 0);
- $fh->read($dat, 12);
- ($ver, $dir_num) = unpack("Nn", $dat);
- $ver == 1 << 16 || $ver == unpack('N', 'OTTO') || $ver == 0x74727565 or return undef; # support Mac sfnts
-
- for ($i = 0; $i < $dir_num; $i++)
- {
- $fh->read($dat, 16) || die "Reading table entry";
- ($name, $check, $off, $len) = unpack("a4NNN", $dat);
- $self->{$name} = $self->{' PARENT'}->find($self, $name, $check, $off, $len) && next
- if (defined $self->{' PARENT'});
- $type = $tables{$name} || 'Font::TTF::Table';
- $t = $type;
- if ($^O eq "MacOS")
- { $t =~ s/^|::/:/oig; }
- else
- { $t =~ s|::|/|oig; }
- require "$t.pm";
- $self->{$name} = $type->new(PARENT => $self,
- NAME => $name,
- INFILE => $fh,
- OFFSET => $off,
- LENGTH => $len,
- CSUM => $check);
- }
-
- foreach $t ('head', 'maxp')
- { $self->{$t}->read if defined $self->{$t}; }
-
- $self;
-}
-
-
-=head2 $f->out($fname [, @tablelist])
-
-Writes a TTF file consisting of the tables in tablelist. The list is checked to
-ensure that only tables that exist are output. (This means that you can't have
-non table information stored in the font object with key length of exactly 4)
-
-In many cases the user simply wants to output all the tables in alphabetical order.
-This can be done by not including a @tablelist, in which case the subroutine will
-output all the defined tables in the font in alphabetical order.
-
-Returns $f on success and undef on failure, including warnings.
-
-All output files must include the C<head> table.
-
-=cut
-
-sub out
-{
- my ($self, $fname, @tlist) = @_;
- my ($fh);
- my ($dat, $numTables, $sRange, $eSel);
- my (%dir, $k, $mloc, $count);
- my ($csum, $lsum, $msum, $loc, $oldloc, $len, $shift);
-
- unless (ref($fname))
- {
- $fh = IO::File->new("+>$fname") || return warn("Unable to open $fname for writing"), undef;
- binmode $fh;
- } else
- { $fh = $fname; }
-
- $self->{' oname'} = $fname;
- $self->{' outfile'} = $fh;
-
- if ($self->{' wantsig'})
- {
- $self->{' nocsum'} = 1;
-# $self->{'head'}{'checkSumAdjustment'} = 0;
- $self->{' tempDSIG'} = $self->{'DSIG'};
- $self->{' tempcsum'} = $self->{'head'}{' CSUM'};
- delete $self->{'DSIG'};
- @tlist = sort {$self->{$a}{' OFFSET'} <=> $self->{$b}{' OFFSET'}}
- grep (length($_) == 4 && defined $self->{$_}, keys %$self) if ($#tlist < 0);
- }
- elsif ($#tlist < 0)
- { @tlist = sort keys %$self; }
-
- @tlist = grep(length($_) == 4 && defined $self->{$_}, @tlist);
- $numTables = $#tlist + 1;
- $numTables++ if ($self->{' wantsig'});
-
- ($numTables, $sRange, $eSel, $shift) = Font::TTF::Utils::TTF_bininfo($numTables, 16);
- $dat = pack("Nnnnn", 1 << 16, $numTables, $sRange, $eSel, $shift);
- $fh->print($dat);
- $msum = unpack("%32N*", $dat);
-
-# reserve place holders for each directory entry
- foreach $k (@tlist)
- {
- $dir{$k} = pack("A4NNN", $k, 0, 0, 0);
- $fh->print($dir{$k});
- }
-
- $fh->print(pack('A4NNN', '', 0, 0, 0)) if ($self->{' wantsig'});
-
- $loc = $fh->tell();
- if ($loc & 3)
- {
- $fh->print(substr("\000" x 4, $loc & 3));
- $loc += 4 - ($loc & 3);
- }
-
- foreach $k (@tlist)
- {
- $oldloc = $loc;
- $self->{$k}->out($fh);
- $loc = $fh->tell();
- $len = $loc - $oldloc;
- if ($loc & 3)
- {
- $fh->print(substr("\000" x 4, $loc & 3));
- $loc += 4 - ($loc & 3);
- }
- $fh->seek($oldloc, 0);
- $csum = 0; $mloc = $loc;
- while ($mloc > $oldloc)
- {
- $count = ($mloc - $oldloc > 4096) ? 4096 : $mloc - $oldloc;
- $fh->read($dat, $count);
- $csum += unpack("%32N*", $dat);
-# this line ensures $csum stays within 32 bit bounds, clipping as necessary
- if ($csum > 0xffffffff) { $csum -= 0xffffffff; $csum--; }
- $mloc -= $count;
- }
- $dir{$k} = pack("A4NNN", $k, $csum, $oldloc, $len);
- $msum += $csum + unpack("%32N*", $dir{$k});
- while ($msum > 0xffffffff) { $msum -= 0xffffffff; $msum--; }
- $fh->seek($loc, 0);
- }
-
- unless ($self->{' nocsum'}) # assuming we want a file checksum
- {
-# Now we need to sort out the head table's checksum
- if (!defined $dir{'head'})
- { # you have to have a head table
- $fh->close();
- return warn("No 'head' table to output in $fname"), undef;
- }
- ($csum, $loc, $len) = unpack("x4NNN", $dir{'head'});
- $fh->seek($loc + 8, 0);
- $fh->read($dat, 4);
- $lsum = unpack("N", $dat);
- if ($lsum != 0)
- {
- $csum -= $lsum;
- if ($csum < 0) { $csum += 0xffffffff; $csum++; }
- $msum -= $lsum * 2; # twice (in head and in csum)
- while ($msum < 0) { $msum += 0xffffffff; $msum++; }
- }
- $lsum = 0xB1B0AFBA - $msum;
- $fh->seek($loc + 8, 0);
- $fh->print(pack("N", $lsum));
- $dir{'head'} = pack("A4NNN", 'head', $csum, $loc, $len);
- } elsif ($self->{' wantsig'})
- {
- if (!defined $dir{'head'})
- { # you have to have a head table
- $fh->close();
- return warn("No 'head' table to output in $fname"), undef;
- }
- ($csum, $loc, $len) = unpack("x4NNN", $dir{'head'});
- $fh->seek($loc + 8, 0);
- $fh->print(pack("N", 0));
-# $dir{'head'} = pack("A4NNN", 'head', $self->{' tempcsum'}, $loc, $len);
- }
-
-# Now we can output the directory again
- if ($self->{' wantsig'})
- { @tlist = sort @tlist; }
- $fh->seek(12, 0);
- foreach $k (@tlist)
- { $fh->print($dir{$k}); }
- $fh->print(pack('A4NNN', '', 0, 0, 0)) if ($self->{' wantsig'});
- $fh->close();
- $self;
-}
-
-
-=head2 $f->out_xml($filename [, @tables])
-
-Outputs the font in XML format
-
-=cut
-
-sub out_xml
-{
- my ($self, $fname, @tlist) = @_;
- my ($fh, $context, $numTables, $k);
-
- $context->{'indent'} = ' ' x 4;
-
- unless (ref($fname))
- {
- $fh = IO::File->new("+>$fname") || return warn("Unable to open $fname"), undef;
- binmode $fh;
- } else
- { $fh = $fname; }
-
- unless (scalar @tlist > 0)
- {
- @tlist = sort keys %$self;
- @tlist = grep(length($_) == 4 && defined $self->{$_}, @tlist);
- }
- $numTables = $#tlist + 1;
-
- $context->{'fh'} = $fh;
- $fh->print("<?xml version='1.0' encoding='UTF-8'?>\n");
- $fh->print("<font tables='$numTables'>\n\n");
-
- foreach $k (@tlist)
- {
- $fh->print("<table name='$k'>\n");
- $self->{$k}->out_xml($context, $context->{'indent'});
- $fh->print("</table>\n");
- }
-
- $fh->print("</font>\n");
- $fh->close;
- $self;
-}
-
-
-=head2 $f->XML_start($context, $tag, %attrs)
-
-Handles start messages from the XML parser. Of particular interest to us are <font> and
-<table>.
-
-=cut
-
-sub XML_start
-{
- my ($self, $context, $tag, %attrs) = @_;
- my ($name, $type, $t);
-
- if ($tag eq 'font')
- { $context->{'tree'}[-1] = $self; }
- elsif ($tag eq 'table')
- {
- $name = $attrs{'name'};
- unless (defined $self->{$name})
- {
- $type = $tables{$name} || 'Font::TTF::Table';
- $t = $type;
- if ($^O eq "MacOS")
- { $t =~ s/^|::/:/oig; }
- else
- { $t =~ s|::|/|oig; }
- require "$t.pm";
- $self->{$name} = $type->new('PARENT' => $self, 'NAME' => $name, 'read' => 1);
- }
- $context->{'receiver'} = ($context->{'tree'}[-1] = $self->{$name});
- }
- $context;
-}
-
-
-sub XML_end
-{
- my ($self) = @_;
- my ($context, $tag, %attrs) = @_;
- my ($i);
-
- return undef unless ($tag eq 'table' && $attrs{'name'} eq 'loca');
- if (defined $context->{'glyphs'} && $context->{'glyphs'} ne $self->{'loca'}{'glyphs'})
- {
- for ($i = 0; $i <= $#{$context->{'glyphs'}}; $i++)
- { $self->{'loca'}{'glyphs'}[$i] = $context->{'glyphs'}[$i] if defined $context->{'glyphs'}[$i]; }
- $context->{'glyphs'} = $self->{'loca'}{'glyphs'};
- }
- return undef;
-}
-
-=head2 $f->update
-
-Sends update to all the tables in the font and then resets all the isDirty
-flags on each table. The data structure in now consistent as a font (we hope).
-
-=cut
-
-sub update
-{
- my ($self) = @_;
-
- $self->tables_do(sub { $_[0]->update; });
-
- $self;
-}
-
-=head2 $f->dirty
-
-Dirties all the tables in the font
-
-=cut
-
-sub dirty
-{ $_[0]->tables_do(sub { $_[0]->dirty; }); $_[0]; }
-
-=head2 $f->tables_do(&func)
-
-Calls &func for each table in the font. Calls the table in alphabetical sort
-order as per the order in the directory:
-
- &func($table, $name);
-
-=cut
-
-sub tables_do
-{
- my ($self, $func) = @_;
- my ($t);
-
- foreach $t (sort grep {length($_) == 4} keys %$self)
- { &$func($self->{$t}, $t); }
- $self;
-}
-
-
-=head2 $f->release
-
-Releases ALL of the memory used by the TTF font and all of its component
-objects. After calling this method, do B<NOT> expect to have anything left in
-the C<Font::TTF::Font> object.
-
-B<NOTE>, that it is important that you call this method on any
-C<Font::TTF::Font> object when you wish to destruct it and free up its memory.
-Internally, we track things in a structure that can result in circular
-references, and without calling 'C<release()>' these will not properly get
-cleaned up by Perl. Once you've called this method, though, don't expect to be
-able to do anything else with the C<Font::TTF::Font> object; it'll have B<no>
-internal state whatsoever.
-
-B<Developer note:> As part of the brute-force cleanup done here, this method
-will throw a warning message whenever unexpected key values are found within
-the C<Font::TTF::Font> object. This is done to help ensure that any unexpected
-and unfreed values are brought to your attention so that you can bug us to keep
-the module updated properly; otherwise the potential for memory leaks due to
-dangling circular references will exist.
-
-=cut
-
-sub release
-{
- my ($self) = @_;
-
-# delete stuff that we know we can, here
-
- my @tofree = map { delete $self->{$_} } keys %{$self};
-
- while (my $item = shift @tofree)
- {
- my $ref = ref($item);
- if (UNIVERSAL::can($item, 'release'))
- { $item->release(); }
- elsif ($ref eq 'ARRAY')
- { push( @tofree, @{$item} ); }
- elsif (UNIVERSAL::isa($ref, 'HASH'))
- { release($item); }
- }
-
-# check that everything has gone - it better had!
- foreach my $key (keys %{$self})
- { warn ref($self) . " still has '$key' key left after release.\n"; }
-}
-
-1;
-
-=head1 BUGS
-
-Bugs abound aplenty I am sure. There is a lot of code here and plenty of scope.
-The parts of the code which haven't been implemented yet are:
-
-=over 4
-
-=item Post
-
-Version 4 format types are not supported yet.
-
-=item Cmap
-
-Format type 2 (MBCS) has not been implemented yet and therefore may cause
-somewhat spurious results for this table type.
-
-=item Kern
-
-Only type 0 & type 2 tables are supported (type 1 & type 3 yet to come).
-
-=item TTC
-
-The current Font::TTF::Font::out method does not support the writing of TrueType
-Collections.
-
-=back
-
-In addition there are weaknesses or features of this module library
-
-=over 4
-
-=item *
-
-There is very little (or no) error reporting. This means that if you have
-garbled data or garbled data structures, then you are liable to generate duff
-fonts.
-
-=item *
-
-The exposing of the internal data structures everywhere means that doing
-radical re-structuring is almost impossible. But it stop the code from becoming
-ridiculously large.
-
-=back
-
-Apart from these, I try to keep the code in a state of "no known bugs", which
-given the amount of testing this code has had, is not a guarantee of high
-quality, yet.
-
-For more details see the appropriate class files.
-
-=head1 AUTHOR
-
-Martin Hosken Martin_Hosken at sil.org
-
-Copyright Martin Hosken 1998.
-
-No warranty or expression of effectiveness, least of all regarding anyone's
-safety, is implied in this software or documentation.
-
-=head2 Licensing
-
-The Perl TTF module is licensed under the Perl Artistic License.
-
+package Font::TTF::Font;
+
+=head1 NAME
+
+Font::TTF::Font - Memory representation of a font
+
+=head1 SYNOPSIS
+
+Here is the regression test (you provide your own font). Run it once and then
+again on the output of the first run. There should be no differences between
+the outputs of the two runs.
+
+ $f = Font::TTF::Font->open($ARGV[0]);
+
+ # force a read of all the tables
+ $f->tables_do(sub { $_[0]->read; });
+
+ # force read of all glyphs (use read_dat to use lots of memory!)
+ # $f->{'loca'}->glyphs_do(sub { $_[0]->read; });
+ $f->{'loca'}->glyphs_do(sub { $_[0]->read_dat; });
+ # NB. no need to $g->update since $f->{'glyf'}->out will do it for us
+
+ $f->out($ARGV[1]);
+ $f->release; # clear up memory forcefully!
+
+=head1 DESCRIPTION
+
+A Truetype font consists of a header containing a directory of tables which
+constitute the rest of the file. This class holds that header and directory and
+also creates objects of the appropriate type for each table within the font.
+Note that it does not read each table into memory, but creates a short reference
+which can be read using the form:
+
+ $f->{$tablename}->read;
+
+Classes are included that support many of the different TrueType tables. For
+those for which no special code exists, the table type C<table> is used, which
+defaults to L<Font::TTF::Table>. The current tables which are supported are:
+
+ table Font::TTF::Table - for unknown tables
+ GDEF Font::TTF::GDEF
+ GPOS Font::TTF::GPOS
+ GSUB Font::TTF::GSUB
+ LTSH Font::TTF::LTSH
+ OS/2 Font::TTF::OS_2
+ PCLT Font::TTF::PCLT
+ bsln Font::TTF::Bsln
+ cmap Font::TTF::Cmap - see also Font::TTF::OldCmap
+ cvt Font::TTF::Cvt_
+ fdsc Font::TTF::Fdsc
+ feat Font::TTF::Feat
+ fmtx Font::TTF::Fmtx
+ fpgm Font::TTF::Fpgm
+ glyf Font::TTF::Glyf - see also Font::TTF::Glyph
+ hdmx Font::TTF::Hdmx
+ head Font::TTF::Head
+ hhea Font::TTF::Hhea
+ hmtx Font::TTF::Hmtx
+ kern Font::TTF::Kern - see alternative Font::TTF::AATKern
+ loca Font::TTF::Loca
+ maxp Font::TTF::Maxp
+ mort Font::TTF::Mort - see also Font::TTF::OldMort
+ name Font::TTF::Name
+ post Font::TTF::Post
+ prep Font::TTF::Prep
+ prop Font::TTF::Prop
+ vhea Font::TTF::Vhea
+ vmtx Font::TTF::Vmtx
+
+Links are:
+
+L<Font::TTF::Table> L<Font::TTF::GDEF> L<Font::TTF::GPOS> L<Font::TTF::GSUB> L<Font::TTF::LTSH>
+L<Font::TTF::OS_2> L<Font::TTF::PCLT> L<Font::TTF::Bsln> L<Font::TTF::Cmap> L<Font::TTF::Cvt_>
+L<Font::TTF::Fdsc> L<Font::TTF::Feat> L<Font::TTF::Fmtx> L<Font::TTF::Fpgm> L<Font::TTF::Glyf>
+L<Font::TTF::Hdmx> L<Font::TTF::Head> L<Font::TTF::Hhea> L<Font::TTF::Hmtx> L<Font::TTF::Kern>
+L<Font::TTF::Loca> L<Font::TTF::Maxp> L<Font::TTF::Mort> L<Font::TTF::Name> L<Font::TTF::Post>
+L<Font::TTF::Prep> L<Font::TTF::Prop> L<Font::TTF::Vhea> L<Font::TTF::Vmtx> L<Font::TTF::OldCmap>
+L<Font::TTF::Glyph> L<Font::TTF::AATKern> L<Font::TTF::OldMort>
+
+
+=head1 INSTANCE VARIABLES
+
+Instance variables begin with a space (and have lengths greater than the 4
+characters which make up table names).
+
+=over
+
+=item nocsum
+
+This is used during output to disable the creation of the file checksum in the
+head table. For example, during DSIG table creation, this flag will be set to
+ensure that the file checksum is left at zero.
+
+=item fname (R)
+
+Contains the filename of the font which this object was read from.
+
+=item INFILE (P)
+
+The file handle which reflects the source file for this font.
+
+=item OFFSET (P)
+
+Contains the offset from the beginning of the read file of this particular
+font directory, thus providing support for TrueType Collections.
+
+=back
+
+=head1 METHODS
+
+=cut
+
+use IO::File;
+
+use strict;
+use vars qw(%tables $VERSION $dumper);
+use Symbol();
+
+require 5.004;
+
+$VERSION = 0.37; # MJPH 7-OCT-2005 Force hhea update if dirty, give more OS/2 stuff in update
+# $VERSION = 0.36; # MJPH 19-AUG-2005 Change cmap::reverse api to be opts based
+# $VERSION = 0.35; # MJPH 4-MAY-2004 Various fixes to OpenType stuff, separate off scripts
+# $VERSION = 0.34; # MJPH 22-MAY-2003 Update PSNames to latest AGL
+# $VERSION = 0.33; # MJPH 9-OCT-2002 Support CFF OpenType (just by version=='OTTO'?!)
+# $VERSION = 0.32; # MJPH 2-OCT-2002 Bug fixes to TTFBuilder, new methods and some
+# extension table support in Ttopen and Coverage
+# $VERSION = 0.31; # MJPH 1-JUL-2002 fix read format 12 cmap (bart at cs.pdx.edu)
+# improve surrogate support in ttfremap
+# fix return warn to return warn,undef
+# ensure correct indexToLocFormat
+# $VERSION = 0.30; # MJPH 28-MAY-2002 add updated release
+# $VERSION = 0.29; # MJPH 9-APR-2002 update ttfbuilder, sort out surrogates
+# $VERSION = 0.28; # MJPH 13-MAR-2002 update ttfbuilder, add Font::TTF::Cmap::ms_enc()
+# $VERSION = 0.27; # MJPH 6-FEB-2002 update ttfbuilder, support no fpgm, no more __DATA__
+# $VERSION = 0.26; # MJPH 19-SEP-2001 Update ttfbuilder
+# $VERSION = 0.25; # MJPH 18-SEP-2001 problems in update of head
+# $VERSION = 0.24; # MJPH 1-AUG-2001 Sort out update
+# $VERSION = 0.23; # GST 30-MAY-2001 Memory leak fixed
+# $VERSION = 0.22; # MJPH 09-APR-2001 Ensure all of AAT stuff included
+# $VERSION = 0.21; # MJPH 23-MAR-2001 Improve Opentype support
+# $VERSION = 0.20; # MJPH 13-JAN-2001 Add XML output and some of XML input, AAT & OT tables
+# $VERSION = 0.19; # MJPH 29-SEP-2000 Add cmap::is_unicode, debug makefile.pl
+# $VERSION = 0.18; # MJPH 21-JUL-2000 Debug Utils::TTF_bininfo
+# $VERSION = 0.17; # MJPH 16-JUN-2000 Add utf8 support to names
+# $VERSION = 0.16; # MJPH 26-APR-2000 Mark read tables as read, tidy up POD
+# $VERSION = 0.15; # MJPH 5-FEB-2000 Ensure right versions released
+# $VERSION = 0.14; # MJPH 11-SEP-1999 Sort out Unixisms, agian!
+# $VERSION = 0.13; # MJPH 9-SEP-1999 Add empty, debug update_bbox
+# $VERSION = 0.12; # MJPH 22-JUL-1999 Add update_bbox
+# $VERSION = 0.11; # MJPH 7-JUL-1999 Don't store empties in cmaps
+# $VERSION = 0.10; # MJPH 21-JUN-1999 Use IO::File
+# $VERSION = 0.09; # MJPH 9-JUN-1999 Add 5.004 require, minor tweeks in cmap
+# $VERSION = 0.08; # MJPH 19-MAY-1999 Sort out line endings for Unix
+# $VERSION = 0.07; # MJPH 28-APR-1999 Get the regression tests to work
+# $VERSION = 0.06; # MJPH 26-APR-1999 Start to add to CVS, correct MANIFEST.SKIP
+# $VERSION = 0.05; # MJPH 13-APR-1999 See changes for 0.05
+# $VERSION = 0.04; # MJPH 13-MAR-1999 Tidy up Tarball
+# $VERSION = 0.03; # MJPH 9-MAR-1999 Move to Font::TTF for CPAN
+# $VERSION = 0.02; # MJPH 12-FEB-1999 Add support for ' nocsum' for DSIGS
+# $VERSION = 0.0001;
+
+%tables = (
+ 'table' => 'Font::TTF::Table',
+ 'GDEF' => 'Font::TTF::GDEF',
+ 'GPOS' => 'Font::TTF::GPOS',
+ 'GSUB' => 'Font::TTF::GSUB',
+ 'LTSH' => 'Font::TTF::LTSH',
+ 'OS/2' => 'Font::TTF::OS_2',
+ 'PCLT' => 'Font::TTF::PCLT',
+ 'bsln' => 'Font::TTF::Bsln',
+ 'cmap' => 'Font::TTF::Cmap',
+ 'cvt ' => 'Font::TTF::Cvt_',
+ 'fdsc' => 'Font::TTF::Fdsc',
+ 'feat' => 'Font::TTF::Feat',
+ 'fmtx' => 'Font::TTF::Fmtx',
+ 'fpgm' => 'Font::TTF::Fpgm',
+ 'glyf' => 'Font::TTF::Glyf',
+ 'hdmx' => 'Font::TTF::Hdmx',
+ 'head' => 'Font::TTF::Head',
+ 'hhea' => 'Font::TTF::Hhea',
+ 'hmtx' => 'Font::TTF::Hmtx',
+ 'kern' => 'Font::TTF::Kern',
+ 'loca' => 'Font::TTF::Loca',
+ 'maxp' => 'Font::TTF::Maxp',
+ 'mort' => 'Font::TTF::Mort',
+ 'name' => 'Font::TTF::Name',
+ 'post' => 'Font::TTF::Post',
+ 'prep' => 'Font::TTF::Prep',
+ 'prop' => 'Font::TTF::Prop',
+ 'vhea' => 'Font::TTF::Vhea',
+ 'vmtx' => 'Font::TTF::Vmtx',
+ );
+
+# This is special code because I am fed up of every time I x a table in the debugger
+# I get the whole font printed. Thus substitutes my 3 line change to dumpvar into
+# the debugger. Clunky, but nice. You are welcome to a copy if you want one.
+
+BEGIN {
+ my ($p);
+
+ foreach $p (@INC)
+ {
+ if (-f "$p/mydumpvar.pl")
+ {
+ $dumper = 'mydumpvar.pl';
+ last;
+ }
+ }
+ $dumper ||= 'dumpvar.pl';
+}
+
+sub main::dumpValue
+{ do $dumper; &main::dumpValue; }
+
+
+=head2 Font::TTF::Font->AddTable($tablename, $class)
+
+Adds the given class to be used when representing the given table name. It also
+'requires' the class for you.
+
+=cut
+
+sub AddTable
+{
+ my ($class, $table, $useclass) = @_;
+
+ $tables{$table} = $useclass;
+# $useclass =~ s|::|/|oig;
+# require "$useclass.pm";
+}
+
+
+=head2 Font::TTF::Font->Init
+
+For those people who like making fonts without reading them. This subroutine
+will require all the table code for the various table types for you. Not
+needed if using Font::TTF::Font::read before using a table.
+
+=cut
+
+sub Init
+{
+ my ($class) = @_;
+ my ($t);
+
+ foreach $t (keys %tables)
+ {
+ $t =~ s|::|/|oig;
+ require "$t.pm";
+ }
+}
+
+=head2 Font::TTF::Font->new(%props)
+
+Creates a new font object and initialises with the given properties. This is
+primarily for use when a TTF is embedded somewhere. Notice that the properties
+are automatically preceded by a space when inserted into the object. This is in
+order that fields do not clash with tables.
+
+=cut
+
+sub new
+{
+ my ($class, %props) = @_;
+ my ($self) = {};
+
+ bless $self, $class;
+
+ foreach (keys %props)
+ { $self->{" $_"} = $props{$_}; }
+ $self;
+}
+
+
+=head2 Font::TTF::Font->open($fname)
+
+Reads the header and directory for the given font file and creates appropriate
+objects for each table in the font.
+
+=cut
+
+sub open
+{
+ my ($class, $fname) = @_;
+ my ($fh);
+ my ($self) = {};
+
+ unless (ref($fname))
+ {
+ $fh = IO::File->new($fname) or return undef;
+ binmode $fh;
+ } else
+ { $fh = $fname; }
+
+ $self->{' INFILE'} = $fh;
+ $self->{' fname'} = $fname;
+ $self->{' OFFSET'} = 0;
+ bless $self, $class;
+
+ $self->read;
+}
+
+=head2 $f->read
+
+Reads a Truetype font directory starting from the current location in the file.
+This has been separated from the C<open> function to allow support for embedded
+TTFs for example in TTCs. Also reads the C<head> and C<maxp> tables immediately.
+
+=cut
+
+sub read
+{
+ my ($self) = @_;
+ my ($fh) = $self->{' INFILE'};
+ my ($dat, $i, $ver, $dir_num, $type, $name, $check, $off, $len, $t);
+
+ $fh->seek($self->{' OFFSET'}, 0);
+ $fh->read($dat, 12);
+ ($ver, $dir_num) = unpack("Nn", $dat);
+ $ver == 1 << 16 || $ver == unpack('N', 'OTTO') || $ver == 0x74727565 or return undef; # support Mac sfnts
+
+ for ($i = 0; $i < $dir_num; $i++)
+ {
+ $fh->read($dat, 16) || die "Reading table entry";
+ ($name, $check, $off, $len) = unpack("a4NNN", $dat);
+ $self->{$name} = $self->{' PARENT'}->find($self, $name, $check, $off, $len) && next
+ if (defined $self->{' PARENT'});
+ $type = $tables{$name} || 'Font::TTF::Table';
+ $t = $type;
+ if ($^O eq "MacOS")
+ { $t =~ s/^|::/:/oig; }
+ else
+ { $t =~ s|::|/|oig; }
+ require "$t.pm";
+ $self->{$name} = $type->new(PARENT => $self,
+ NAME => $name,
+ INFILE => $fh,
+ OFFSET => $off,
+ LENGTH => $len,
+ CSUM => $check);
+ }
+
+ foreach $t ('head', 'maxp')
+ { $self->{$t}->read if defined $self->{$t}; }
+
+ $self;
+}
+
+
+=head2 $f->out($fname [, @tablelist])
+
+Writes a TTF file consisting of the tables in tablelist. The list is checked to
+ensure that only tables that exist are output. (This means that you can't have
+non table information stored in the font object with key length of exactly 4)
+
+In many cases the user simply wants to output all the tables in alphabetical order.
+This can be done by not including a @tablelist, in which case the subroutine will
+output all the defined tables in the font in alphabetical order.
+
+Returns $f on success and undef on failure, including warnings.
+
+All output files must include the C<head> table.
+
+=cut
+
+sub out
+{
+ my ($self, $fname, @tlist) = @_;
+ my ($fh);
+ my ($dat, $numTables, $sRange, $eSel);
+ my (%dir, $k, $mloc, $count);
+ my ($csum, $lsum, $msum, $loc, $oldloc, $len, $shift);
+
+ unless (ref($fname))
+ {
+ $fh = IO::File->new("+>$fname") || return warn("Unable to open $fname for writing"), undef;
+ binmode $fh;
+ } else
+ { $fh = $fname; }
+
+ $self->{' oname'} = $fname;
+ $self->{' outfile'} = $fh;
+
+ if ($self->{' wantsig'})
+ {
+ $self->{' nocsum'} = 1;
+# $self->{'head'}{'checkSumAdjustment'} = 0;
+ $self->{' tempDSIG'} = $self->{'DSIG'};
+ $self->{' tempcsum'} = $self->{'head'}{' CSUM'};
+ delete $self->{'DSIG'};
+ @tlist = sort {$self->{$a}{' OFFSET'} <=> $self->{$b}{' OFFSET'}}
+ grep (length($_) == 4 && defined $self->{$_}, keys %$self) if ($#tlist < 0);
+ }
+ elsif ($#tlist < 0)
+ { @tlist = sort keys %$self; }
+
+ @tlist = grep(length($_) == 4 && defined $self->{$_}, @tlist);
+ $numTables = $#tlist + 1;
+ $numTables++ if ($self->{' wantsig'});
+
+ ($numTables, $sRange, $eSel, $shift) = Font::TTF::Utils::TTF_bininfo($numTables, 16);
+ $dat = pack("Nnnnn", 1 << 16, $numTables, $sRange, $eSel, $shift);
+ $fh->print($dat);
+ $msum = unpack("%32N*", $dat);
+
+# reserve place holders for each directory entry
+ foreach $k (@tlist)
+ {
+ $dir{$k} = pack("A4NNN", $k, 0, 0, 0);
+ $fh->print($dir{$k});
+ }
+
+ $fh->print(pack('A4NNN', '', 0, 0, 0)) if ($self->{' wantsig'});
+
+ $loc = $fh->tell();
+ if ($loc & 3)
+ {
+ $fh->print(substr("\000" x 4, $loc & 3));
+ $loc += 4 - ($loc & 3);
+ }
+
+ foreach $k (@tlist)
+ {
+ $oldloc = $loc;
+ $self->{$k}->out($fh);
+ $loc = $fh->tell();
+ $len = $loc - $oldloc;
+ if ($loc & 3)
+ {
+ $fh->print(substr("\000" x 4, $loc & 3));
+ $loc += 4 - ($loc & 3);
+ }
+ $fh->seek($oldloc, 0);
+ $csum = 0; $mloc = $loc;
+ while ($mloc > $oldloc)
+ {
+ $count = ($mloc - $oldloc > 4096) ? 4096 : $mloc - $oldloc;
+ $fh->read($dat, $count);
+ $csum += unpack("%32N*", $dat);
+# this line ensures $csum stays within 32 bit bounds, clipping as necessary
+ if ($csum > 0xffffffff) { $csum -= 0xffffffff; $csum--; }
+ $mloc -= $count;
+ }
+ $dir{$k} = pack("A4NNN", $k, $csum, $oldloc, $len);
+ $msum += $csum + unpack("%32N*", $dir{$k});
+ while ($msum > 0xffffffff) { $msum -= 0xffffffff; $msum--; }
+ $fh->seek($loc, 0);
+ }
+
+ unless ($self->{' nocsum'}) # assuming we want a file checksum
+ {
+# Now we need to sort out the head table's checksum
+ if (!defined $dir{'head'})
+ { # you have to have a head table
+ $fh->close();
+ return warn("No 'head' table to output in $fname"), undef;
+ }
+ ($csum, $loc, $len) = unpack("x4NNN", $dir{'head'});
+ $fh->seek($loc + 8, 0);
+ $fh->read($dat, 4);
+ $lsum = unpack("N", $dat);
+ if ($lsum != 0)
+ {
+ $csum -= $lsum;
+ if ($csum < 0) { $csum += 0xffffffff; $csum++; }
+ $msum -= $lsum * 2; # twice (in head and in csum)
+ while ($msum < 0) { $msum += 0xffffffff; $msum++; }
+ }
+ $lsum = 0xB1B0AFBA - $msum;
+ $fh->seek($loc + 8, 0);
+ $fh->print(pack("N", $lsum));
+ $dir{'head'} = pack("A4NNN", 'head', $csum, $loc, $len);
+ } elsif ($self->{' wantsig'})
+ {
+ if (!defined $dir{'head'})
+ { # you have to have a head table
+ $fh->close();
+ return warn("No 'head' table to output in $fname"), undef;
+ }
+ ($csum, $loc, $len) = unpack("x4NNN", $dir{'head'});
+ $fh->seek($loc + 8, 0);
+ $fh->print(pack("N", 0));
+# $dir{'head'} = pack("A4NNN", 'head', $self->{' tempcsum'}, $loc, $len);
+ }
+
+# Now we can output the directory again
+ if ($self->{' wantsig'})
+ { @tlist = sort @tlist; }
+ $fh->seek(12, 0);
+ foreach $k (@tlist)
+ { $fh->print($dir{$k}); }
+ $fh->print(pack('A4NNN', '', 0, 0, 0)) if ($self->{' wantsig'});
+ $fh->close();
+ $self;
+}
+
+
+=head2 $f->out_xml($filename [, @tables])
+
+Outputs the font in XML format
+
+=cut
+
+sub out_xml
+{
+ my ($self, $fname, @tlist) = @_;
+ my ($fh, $context, $numTables, $k);
+
+ $context->{'indent'} = ' ' x 4;
+
+ unless (ref($fname))
+ {
+ $fh = IO::File->new("+>$fname") || return warn("Unable to open $fname"), undef;
+ binmode $fh;
+ } else
+ { $fh = $fname; }
+
+ unless (scalar @tlist > 0)
+ {
+ @tlist = sort keys %$self;
+ @tlist = grep(length($_) == 4 && defined $self->{$_}, @tlist);
+ }
+ $numTables = $#tlist + 1;
+
+ $context->{'fh'} = $fh;
+ $fh->print("<?xml version='1.0' encoding='UTF-8'?>\n");
+ $fh->print("<font tables='$numTables'>\n\n");
+
+ foreach $k (@tlist)
+ {
+ $fh->print("<table name='$k'>\n");
+ $self->{$k}->out_xml($context, $context->{'indent'});
+ $fh->print("</table>\n");
+ }
+
+ $fh->print("</font>\n");
+ $fh->close;
+ $self;
+}
+
+
+=head2 $f->XML_start($context, $tag, %attrs)
+
+Handles start messages from the XML parser. Of particular interest to us are <font> and
+<table>.
+
+=cut
+
+sub XML_start
+{
+ my ($self, $context, $tag, %attrs) = @_;
+ my ($name, $type, $t);
+
+ if ($tag eq 'font')
+ { $context->{'tree'}[-1] = $self; }
+ elsif ($tag eq 'table')
+ {
+ $name = $attrs{'name'};
+ unless (defined $self->{$name})
+ {
+ $type = $tables{$name} || 'Font::TTF::Table';
+ $t = $type;
+ if ($^O eq "MacOS")
+ { $t =~ s/^|::/:/oig; }
+ else
+ { $t =~ s|::|/|oig; }
+ require "$t.pm";
+ $self->{$name} = $type->new('PARENT' => $self, 'NAME' => $name, 'read' => 1);
+ }
+ $context->{'receiver'} = ($context->{'tree'}[-1] = $self->{$name});
+ }
+ $context;
+}
+
+
+sub XML_end
+{
+ my ($self) = @_;
+ my ($context, $tag, %attrs) = @_;
+ my ($i);
+
+ return undef unless ($tag eq 'table' && $attrs{'name'} eq 'loca');
+ if (defined $context->{'glyphs'} && $context->{'glyphs'} ne $self->{'loca'}{'glyphs'})
+ {
+ for ($i = 0; $i <= $#{$context->{'glyphs'}}; $i++)
+ { $self->{'loca'}{'glyphs'}[$i] = $context->{'glyphs'}[$i] if defined $context->{'glyphs'}[$i]; }
+ $context->{'glyphs'} = $self->{'loca'}{'glyphs'};
+ }
+ return undef;
+}
+
+=head2 $f->update
+
+Sends update to all the tables in the font and then resets all the isDirty
+flags on each table. The data structure in now consistent as a font (we hope).
+
+=cut
+
+sub update
+{
+ my ($self) = @_;
+
+ $self->tables_do(sub { $_[0]->update; });
+
+ $self;
+}
+
+=head2 $f->dirty
+
+Dirties all the tables in the font
+
+=cut
+
+sub dirty
+{ $_[0]->tables_do(sub { $_[0]->dirty; }); $_[0]; }
+
+=head2 $f->tables_do(&func)
+
+Calls &func for each table in the font. Calls the table in alphabetical sort
+order as per the order in the directory:
+
+ &func($table, $name);
+
+=cut
+
+sub tables_do
+{
+ my ($self, $func) = @_;
+ my ($t);
+
+ foreach $t (sort grep {length($_) == 4} keys %$self)
+ { &$func($self->{$t}, $t); }
+ $self;
+}
+
+
+=head2 $f->release
+
+Releases ALL of the memory used by the TTF font and all of its component
+objects. After calling this method, do B<NOT> expect to have anything left in
+the C<Font::TTF::Font> object.
+
+B<NOTE>, that it is important that you call this method on any
+C<Font::TTF::Font> object when you wish to destruct it and free up its memory.
+Internally, we track things in a structure that can result in circular
+references, and without calling 'C<release()>' these will not properly get
+cleaned up by Perl. Once you've called this method, though, don't expect to be
+able to do anything else with the C<Font::TTF::Font> object; it'll have B<no>
+internal state whatsoever.
+
+B<Developer note:> As part of the brute-force cleanup done here, this method
+will throw a warning message whenever unexpected key values are found within
+the C<Font::TTF::Font> object. This is done to help ensure that any unexpected
+and unfreed values are brought to your attention so that you can bug us to keep
+the module updated properly; otherwise the potential for memory leaks due to
+dangling circular references will exist.
+
+=cut
+
+sub release
+{
+ my ($self) = @_;
+
+# delete stuff that we know we can, here
+
+ my @tofree = map { delete $self->{$_} } keys %{$self};
+
+ while (my $item = shift @tofree)
+ {
+ my $ref = ref($item);
+ if (UNIVERSAL::can($item, 'release'))
+ { $item->release(); }
+ elsif ($ref eq 'ARRAY')
+ { push( @tofree, @{$item} ); }
+ elsif (UNIVERSAL::isa($ref, 'HASH'))
+ { release($item); }
+ }
+
+# check that everything has gone - it better had!
+ foreach my $key (keys %{$self})
+ { warn ref($self) . " still has '$key' key left after release.\n"; }
+}
+
+1;
+
+=head1 BUGS
+
+Bugs abound aplenty I am sure. There is a lot of code here and plenty of scope.
+The parts of the code which haven't been implemented yet are:
+
+=over 4
+
+=item Post
+
+Version 4 format types are not supported yet.
+
+=item Cmap
+
+Format type 2 (MBCS) has not been implemented yet and therefore may cause
+somewhat spurious results for this table type.
+
+=item Kern
+
+Only type 0 & type 2 tables are supported (type 1 & type 3 yet to come).
+
+=item TTC
+
+The current Font::TTF::Font::out method does not support the writing of TrueType
+Collections.
+
+=back
+
+In addition there are weaknesses or features of this module library
+
+=over 4
+
+=item *
+
+There is very little (or no) error reporting. This means that if you have
+garbled data or garbled data structures, then you are liable to generate duff
+fonts.
+
+=item *
+
+The exposing of the internal data structures everywhere means that doing
+radical re-structuring is almost impossible. But it stop the code from becoming
+ridiculously large.
+
+=back
+
+Apart from these, I try to keep the code in a state of "no known bugs", which
+given the amount of testing this code has had, is not a guarantee of high
+quality, yet.
+
+For more details see the appropriate class files.
+
+=head1 AUTHOR
+
+Martin Hosken Martin_Hosken at sil.org
+
+Copyright Martin Hosken 1998.
+
+No warranty or expression of effectiveness, least of all regarding anyone's
+safety, is implied in this software or documentation.
+
+=head2 Licensing
+
+The Perl TTF module is licensed under the Perl Artistic License.
+
Modified: packages/libfont-ttf-perl/trunk/lib/Font/TTF/Fpgm.pm
===================================================================
--- packages/libfont-ttf-perl/trunk/lib/Font/TTF/Fpgm.pm 2006-01-17 02:56:43 UTC (rev 1966)
+++ packages/libfont-ttf-perl/trunk/lib/Font/TTF/Fpgm.pm 2006-01-17 03:07:20 UTC (rev 1967)
@@ -1,87 +1,87 @@
-package Font::TTF::Fpgm;
-
-=head1 NAME
-
-Font::TTF::Fpgm - Font program in a TrueType font. Called when a font is loaded
-
-=head1 DESCRIPTION
-
-This is a minimal class adding nothing beyond a table, but is a repository
-for fpgm type information for those processes brave enough to address hinting.
-
-=cut
-
-use strict;
-use vars qw(@ISA $VERSION);
-
- at ISA = qw(Font::TTF::Table);
-
-$VERSION = 0.0001;
-
-=head2 $t->read
-
-Reading this table is simply a process of reading all the data into the RAM
-copy. Nothing more is done with it.
-
-=cut
-
-sub read
-{
- $_[0]->read_dat;
- $_[0]->{' read'} = 1;
-}
-
-=head2 $t->out_xml($context, $depth)
-
-Outputs Fpgm program as XML
-
-=cut
-
-sub out_xml
-{
- my ($self, $context, $depth) = @_;
- my ($fh) = $context->{'fh'};
- my ($dat);
-
- $self->read;
- $dat = Font::TTF::Utils::XML_binhint($self->{' dat'});
- $dat =~ s/\n(?!$)/\n$depth$context->{'indent'}/omg;
- $fh->print("$depth<code>\n");
- $fh->print("$depth$context->{'indent'}$dat");
- $fh->print("$depth</code>\n");
- $self;
-}
-
-
-=head2 $t->XML_end($context, $tag, %attrs)
-
-Parse all that hinting code
-
-=cut
-
-sub XML_end
-{
- my ($self) = shift;
- my ($context, $tag, %attrs) = @_;
-
- if ($tag eq 'code')
- {
- $self->{' dat'} = Font::TTF::Utils::XML_hintbin($context->{'text'});
- return $context;
- } else
- { return $self->SUPER::XML_end(@_); }
-}
-
-1;
-
-=head1 BUGS
-
-None known
-
-=head1 AUTHOR
-
-Martin Hosken Martin_Hosken at sil.org. See L<Font::TTF::Font> for copyright and
-licensing.
-
-=cut
-
+package Font::TTF::Fpgm;
+
+=head1 NAME
+
+Font::TTF::Fpgm - Font program in a TrueType font. Called when a font is loaded
+
+=head1 DESCRIPTION
+
+This is a minimal class adding nothing beyond a table, but is a repository
+for fpgm type information for those processes brave enough to address hinting.
+
+=cut
+
+use strict;
+use vars qw(@ISA $VERSION);
+
+ at ISA = qw(Font::TTF::Table);
+
+$VERSION = 0.0001;
+
+=head2 $t->read
+
+Reading this table is simply a process of reading all the data into the RAM
+copy. Nothing more is done with it.
+
+=cut
+
+sub read
+{
+ $_[0]->read_dat;
+ $_[0]->{' read'} = 1;
+}
+
+=head2 $t->out_xml($context, $depth)
+
+Outputs Fpgm program as XML
+
+=cut
+
+sub out_xml
+{
+ my ($self, $context, $depth) = @_;
+ my ($fh) = $context->{'fh'};
+ my ($dat);
+
+ $self->read;
+ $dat = Font::TTF::Utils::XML_binhint($self->{' dat'});
+ $dat =~ s/\n(?!$)/\n$depth$context->{'indent'}/omg;
+ $fh->print("$depth<code>\n");
+ $fh->print("$depth$context->{'indent'}$dat");
+ $fh->print("$depth</code>\n");
+ $self;
+}
+
+
+=head2 $t->XML_end($context, $tag, %attrs)
+
+Parse all that hinting code
+
+=cut
+
+sub XML_end
+{
+ my ($self) = shift;
+ my ($context, $tag, %attrs) = @_;
+
+ if ($tag eq 'code')
+ {
+ $self->{' dat'} = Font::TTF::Utils::XML_hintbin($context->{'text'});
+ return $context;
+ } else
+ { return $self->SUPER::XML_end(@_); }
+}
+
+1;
+
+=head1 BUGS
+
+None known
+
+=head1 AUTHOR
+
+Martin Hosken Martin_Hosken at sil.org. See L<Font::TTF::Font> for copyright and
+licensing.
+
+=cut
+
Modified: packages/libfont-ttf-perl/trunk/lib/Font/TTF/GDEF.pm
===================================================================
--- packages/libfont-ttf-perl/trunk/lib/Font/TTF/GDEF.pm 2006-01-17 02:56:43 UTC (rev 1966)
+++ packages/libfont-ttf-perl/trunk/lib/Font/TTF/GDEF.pm 2006-01-17 03:07:20 UTC (rev 1967)
@@ -1,310 +1,310 @@
-package Font::TTF::GDEF;
-
-=head1 NAME
-
-Font::TTF::GDEF - Opentype GDEF table support
-
-=head1 DESCRIPTION
-
-The GDEF table contains various global lists of information which are apparantly
-used in other places in an OpenType renderer. But precisely where is open to
-speculation...
-
-=head1 INSTANCE VARIABLES
-
-There are 4 tables in the GDEF table, each with their own structure:
-
-=over 4
-
-=item GLYPH
-
-This is an L<Font::TTF::Coverage> Class Definition table containing information
-as to what type each glyph is.
-
-=item ATTACH
-
-The attach table consists of a coverage table and then attachment points for
-each glyph in the coverage table:
-
-=over 8
-
-=item COVERAGE
-
-This is a coverage table
-
-=item POINTS
-
-This is an array of point elements. Each element is an array of curve points
-corresponding to the attachment points on that glyph. The order of the curve points
-in the array corresponds to the attachment point number specified in the MARKS
-coverage table (see below).
-
-=back
-
-=item LIG
-
-This contains the ligature caret positioning information for ligature glyphs
-
-=over 8
-
-=item COVERAGE
-
-A coverage table to say which glyphs are ligatures
-
-=item LIGS
-
-An array of elements for each ligature. Each element is an array of information
-for each caret position in the ligature (there being number of components - 1 of
-these, generally)
-
-=over 12
-
-=item FMT
-
-This is the format of the information and is important to provide the semantics
-for the value. This value must be set correctly before output
-
-=item VAL
-
-The value which has meaning according to FMT
-
-=item DEVICE
-
-For FMT = 3, a device table is also referenced which is stored here
-
-=back
-
-=back
-
-=item MARKS
-
-Due to confusion in the GDEF specification, this field is currently withdrawn until
-the confusion is resolved. That way, perhaps this stuff will work!
-
-This class definition table stores the mark attachment point numbers for each
-attachment mark, to indicate which attachment point the mark attaches to on its
-base glyph.
-
-=back
-
-
-=head1 METHODS
-
-=cut
-
-use strict;
-use Font::TTF::Table;
-use Font::TTF::Utils;
-use Font::TTF::Ttopen;
-use vars qw(@ISA $new_gdef);
-
- at ISA = qw(Font::TTF::Table);
-$new_gdef = 1;
-
-=head2 $t->read
-
-Reads the table into the data structure
-
-=cut
-
-sub read
-{
- my ($self) = @_;
- my ($fh) = $self->{' INFILE'};
- my ($boff) = $self->{' OFFSET'};
- my ($dat, $goff, $loff, $aoff, $moff, $r, $s, $bloc);
-
- $self->SUPER::read or return $self;
- $bloc = $fh->tell();
- $fh->read($dat, 10);
- ($self->{'Version'}, $goff, $aoff, $loff) = TTF_Unpack('fS3', $dat);
- if ($new_gdef)
- {
- $fh->read($dat, 12);
- ($self->{'Version'}, $goff, $aoff, $loff, $moff) = TTF_Unpack('fS4', $dat);
- }
-
- if ($goff > 0)
- {
- $fh->seek($goff + $boff, 0);
- $self->{'GLYPH'} = Font::TTF::Coverage->new(0)->read($fh);
- }
-
- if ($new_gdef && $moff > 0)
- {
- $fh->seek($moff + $boff, 0);
- $self->{'MARKS'} = Font::TTF::Coverage->new(0)->read($fh);
- }
-
- if ($aoff > 0)
- {
- my ($off, $gcount, $pcount);
-
- $fh->seek($aoff + $boff, 0);
- $fh->read($dat, 4);
- ($off, $gcount) = TTF_Unpack('SS', $dat);
- $fh->read($dat, $gcount << 1);
-
- $fh->seek($aoff + $boff + $off, 0);
- $self->{'ATTACH'}{'COVERAGE'} = Font::TTF::Coverage->new(1)->read($fh);
-
- foreach $r (TTF_Unpack('S*', $dat))
- {
- unless ($r)
- {
- push (@{$self->{'ATTACH'}{'POINTS'}}, []);
- next;
- }
- $fh->seek($aoff + $boff + $r, 0);
- $fh->read($dat, 2);
- $pcount = TTF_Unpack('S', $dat);
- $fh->read($dat, $pcount << 1);
- push (@{$self->{'ATTACH'}{'POINTS'}}, [TTF_Unpack('S*', $dat)]);
- }
- }
-
- if ($loff > 0)
- {
- my ($lcount, $off, $ccount, $srec, $comp);
-
- $fh->seek($loff + $boff, 0);
- $fh->read($dat, 4);
- ($off, $lcount) = TTF_Unpack('SS', $dat);
- $fh->read($dat, $lcount << 1);
-
- $fh->seek($off + $loff + $boff, 0);
- $self->{'LIG'}{'COVERAGE'} = Font::TTF::Coverage->new(1)->read($fh);
-
- foreach $r (TTF_Unpack('S*', $dat))
- {
- $fh->seek($r + $loff + $boff, 0);
- $fh->read($dat, 2);
- $ccount = TTF_Unpack('S', $dat);
- $fh->read($dat, $ccount << 1);
-
- $srec = [];
- foreach $s (TTF_Unpack('S*', $dat))
- {
- $comp = {};
- $fh->seek($s + $r + $loff + $boff, 0);
- $fh->read($dat, 4);
- ($comp->{'FMT'}, $comp->{'VAL'}) = TTF_Unpack('S*', $dat);
- if ($comp->{'FMT'} == 3)
- {
- $fh->read($dat, 2);
- $off = TTF_Unpack('S', $dat);
- if (defined $self->{' CACHE'}{$off + $s + $r})
- { $comp->{'DEVICE'} = $self->{' CACHE'}{$off + $s + $r}; }
- else
- {
- $fh->seek($off + $s + $r + $loff + $boff, 0);
- $comp->{'DEVICE'} = Font::TTF::Delta->new->read($fh);
- $self->{' CACHE'}{$off + $s + $r} = $comp->{'DEVICE'};
- }
- }
- push (@$srec, $comp);
- }
- push (@{$self->{'LIG'}{'LIGS'}}, $srec);
- }
- }
-
- $self;
-}
-
-
-=head2 $t->out($fh)
-
-Writes out this table.
-
-=cut
-
-sub out
-{
- my ($self, $fh) = @_;
- my ($goff, $aoff, $loff, $moff, @offs, $loc1, $coff, $loc);
-
- return $self->SUPER::out($fh) unless $self->{' read'};
-
- $loc = $fh->tell();
- if ($new_gdef)
- { $fh->print(TTF_Pack('fSSSS', $self->{'Version'}, 0, 0, 0, 0)); }
- else
- { $fh->print(TTF_Pack('fSSS', $self->{'Version'}, 0, 0, 0)); }
-
- if (defined $self->{'GLYPH'})
- {
- $goff = $fh->tell() - $loc;
- $self->{'GLYPH'}->out($fh);
- }
-
- if (defined $self->{'ATTACH'})
- {
- my ($r);
-
- $aoff = $fh->tell() - $loc;
- $fh->print(pack('n*', (0) x ($#{$self->{'ATTACH'}{'POINTS'}} + 3)));
- foreach $r (@{$self->{'ATTACH'}{'POINTS'}})
- {
- push (@offs, $fh->tell() - $loc - $aoff);
- $fh->print(pack('n*', $#{$r} + 1, @$r));
- }
- $coff = $fh->tell() - $loc - $aoff;
- $self->{'ATTACH'}{'COVERAGE'}->out($fh);
- $loc1 = $fh->tell();
- $fh->seek($aoff + $loc, 0);
- $fh->print(pack('n*', $coff, $#offs + 1, @offs));
- $fh->seek($loc1, 0);
- }
-
- if (defined $self->{'LIG'})
- {
- my (@reftables, $ltables, $i, $j, $out, $r, $s);
-
- $ltables = {};
- $loff = $fh->tell() - $loc;
- $out = pack('n*',
- Font::TTF::Ttopen->ref_cache($self->{'LIG'}{'COVERAGE'}, $ltables, 0),
- 0, $#{$self->{'LIG'}{'LIGS'}} + 1,
- (0) x ($#{$self->{'LIG'}{'LIGS'}} + 1));
- push (@reftables, [$ltables, 0]);
- $i = 0;
- foreach $r (@{$self->{'LIG'}{'LIGS'}})
- {
- $ltables = {};
- $loc1 = length($out);
- substr($out, ($i << 1) + 4, 2) = TTF_Pack('S', $loc1);
- $out .= pack('n*', $#{$r} + 1, (0) x ($#{$r} + 1));
- @offs = (); $j = 0;
- foreach $s (@$r)
- {
- substr($out, ($j << 1) + 2 + $loc1, 2) =
- TTF_Pack('S', length($out) - $loc1);
- $out .= TTF_Pack('SS', $s->{'FMT'}, $s->{'VAL'});
- $out .= pack('n', Font::TTF::Ttopen->ref_cache($s->{'DEVICE'},
- $ltables, length($out))) if ($s->{'FMT'} == 3);
- $j++;
- }
- push (@reftables, [$ltables, $loc1]);
- $i++;
- }
- Font::TTF::Ttopen::out_final($fh, $out, \@reftables);
- }
-
- if ($new_gdef && defined $self->{'MARKS'})
- {
- $moff = $fh->tell() - $loc;
- $self->{'MARKS'}->out($fh);
- }
-
- $loc1 = $fh->tell();
- $fh->seek($loc + 4, 0);
- if ($new_gdef)
- { $fh->print(TTF_Pack('S4', $goff, $aoff, $loff, $moff)); }
- else
- { $fh->print(TTF_Pack('S3', $goff, $aoff, $loff)); }
- $fh->seek($loc1, 0);
- $self;
-}
-
-1;
-
+package Font::TTF::GDEF;
+
+=head1 NAME
+
+Font::TTF::GDEF - Opentype GDEF table support
+
+=head1 DESCRIPTION
+
+The GDEF table contains various global lists of information which are apparantly
+used in other places in an OpenType renderer. But precisely where is open to
+speculation...
+
+=head1 INSTANCE VARIABLES
+
+There are 4 tables in the GDEF table, each with their own structure:
+
+=over 4
+
+=item GLYPH
+
+This is an L<Font::TTF::Coverage> Class Definition table containing information
+as to what type each glyph is.
+
+=item ATTACH
+
+The attach table consists of a coverage table and then attachment points for
+each glyph in the coverage table:
+
+=over 8
+
+=item COVERAGE
+
+This is a coverage table
+
+=item POINTS
+
+This is an array of point elements. Each element is an array of curve points
+corresponding to the attachment points on that glyph. The order of the curve points
+in the array corresponds to the attachment point number specified in the MARKS
+coverage table (see below).
+
+=back
+
+=item LIG
+
+This contains the ligature caret positioning information for ligature glyphs
+
+=over 8
+
+=item COVERAGE
+
+A coverage table to say which glyphs are ligatures
+
+=item LIGS
+
+An array of elements for each ligature. Each element is an array of information
+for each caret position in the ligature (there being number of components - 1 of
+these, generally)
+
+=over 12
+
+=item FMT
+
+This is the format of the information and is important to provide the semantics
+for the value. This value must be set correctly before output
+
+=item VAL
+
+The value which has meaning according to FMT
+
+=item DEVICE
+
+For FMT = 3, a device table is also referenced which is stored here
+
+=back
+
+=back
+
+=item MARKS
+
+Due to confusion in the GDEF specification, this field is currently withdrawn until
+the confusion is resolved. That way, perhaps this stuff will work!
+
+This class definition table stores the mark attachment point numbers for each
+attachment mark, to indicate which attachment point the mark attaches to on its
+base glyph.
+
+=back
+
+
+=head1 METHODS
+
+=cut
+
+use strict;
+use Font::TTF::Table;
+use Font::TTF::Utils;
+use Font::TTF::Ttopen;
+use vars qw(@ISA $new_gdef);
+
+ at ISA = qw(Font::TTF::Table);
+$new_gdef = 1;
+
+=head2 $t->read
+
+Reads the table into the data structure
+
+=cut
+
+sub read
+{
+ my ($self) = @_;
+ my ($fh) = $self->{' INFILE'};
+ my ($boff) = $self->{' OFFSET'};
+ my ($dat, $goff, $loff, $aoff, $moff, $r, $s, $bloc);
+
+ $self->SUPER::read or return $self;
+ $bloc = $fh->tell();
+ $fh->read($dat, 10);
+ ($self->{'Version'}, $goff, $aoff, $loff) = TTF_Unpack('fS3', $dat);
+ if ($new_gdef)
+ {
+ $fh->read($dat, 12);
+ ($self->{'Version'}, $goff, $aoff, $loff, $moff) = TTF_Unpack('fS4', $dat);
+ }
+
+ if ($goff > 0)
+ {
+ $fh->seek($goff + $boff, 0);
+ $self->{'GLYPH'} = Font::TTF::Coverage->new(0)->read($fh);
+ }
+
+ if ($new_gdef && $moff > 0)
+ {
+ $fh->seek($moff + $boff, 0);
+ $self->{'MARKS'} = Font::TTF::Coverage->new(0)->read($fh);
+ }
+
+ if ($aoff > 0)
+ {
+ my ($off, $gcount, $pcount);
+
+ $fh->seek($aoff + $boff, 0);
+ $fh->read($dat, 4);
+ ($off, $gcount) = TTF_Unpack('SS', $dat);
+ $fh->read($dat, $gcount << 1);
+
+ $fh->seek($aoff + $boff + $off, 0);
+ $self->{'ATTACH'}{'COVERAGE'} = Font::TTF::Coverage->new(1)->read($fh);
+
+ foreach $r (TTF_Unpack('S*', $dat))
+ {
+ unless ($r)
+ {
+ push (@{$self->{'ATTACH'}{'POINTS'}}, []);
+ next;
+ }
+ $fh->seek($aoff + $boff + $r, 0);
+ $fh->read($dat, 2);
+ $pcount = TTF_Unpack('S', $dat);
+ $fh->read($dat, $pcount << 1);
+ push (@{$self->{'ATTACH'}{'POINTS'}}, [TTF_Unpack('S*', $dat)]);
+ }
+ }
+
+ if ($loff > 0)
+ {
+ my ($lcount, $off, $ccount, $srec, $comp);
+
+ $fh->seek($loff + $boff, 0);
+ $fh->read($dat, 4);
+ ($off, $lcount) = TTF_Unpack('SS', $dat);
+ $fh->read($dat, $lcount << 1);
+
+ $fh->seek($off + $loff + $boff, 0);
+ $self->{'LIG'}{'COVERAGE'} = Font::TTF::Coverage->new(1)->read($fh);
+
+ foreach $r (TTF_Unpack('S*', $dat))
+ {
+ $fh->seek($r + $loff + $boff, 0);
+ $fh->read($dat, 2);
+ $ccount = TTF_Unpack('S', $dat);
+ $fh->read($dat, $ccount << 1);
+
+ $srec = [];
+ foreach $s (TTF_Unpack('S*', $dat))
+ {
+ $comp = {};
+ $fh->seek($s + $r + $loff + $boff, 0);
+ $fh->read($dat, 4);
+ ($comp->{'FMT'}, $comp->{'VAL'}) = TTF_Unpack('S*', $dat);
+ if ($comp->{'FMT'} == 3)
+ {
+ $fh->read($dat, 2);
+ $off = TTF_Unpack('S', $dat);
+ if (defined $self->{' CACHE'}{$off + $s + $r})
+ { $comp->{'DEVICE'} = $self->{' CACHE'}{$off + $s + $r}; }
+ else
+ {
+ $fh->seek($off + $s + $r + $loff + $boff, 0);
+ $comp->{'DEVICE'} = Font::TTF::Delta->new->read($fh);
+ $self->{' CACHE'}{$off + $s + $r} = $comp->{'DEVICE'};
+ }
+ }
+ push (@$srec, $comp);
+ }
+ push (@{$self->{'LIG'}{'LIGS'}}, $srec);
+ }
+ }
+
+ $self;
+}
+
+
+=head2 $t->out($fh)
+
+Writes out this table.
+
+=cut
+
+sub out
+{
+ my ($self, $fh) = @_;
+ my ($goff, $aoff, $loff, $moff, @offs, $loc1, $coff, $loc);
+
+ return $self->SUPER::out($fh) unless $self->{' read'};
+
+ $loc = $fh->tell();
+ if ($new_gdef)
+ { $fh->print(TTF_Pack('fSSSS', $self->{'Version'}, 0, 0, 0, 0)); }
+ else
+ { $fh->print(TTF_Pack('fSSS', $self->{'Version'}, 0, 0, 0)); }
+
+ if (defined $self->{'GLYPH'})
+ {
+ $goff = $fh->tell() - $loc;
+ $self->{'GLYPH'}->out($fh);
+ }
+
+ if (defined $self->{'ATTACH'})
+ {
+ my ($r);
+
+ $aoff = $fh->tell() - $loc;
+ $fh->print(pack('n*', (0) x ($#{$self->{'ATTACH'}{'POINTS'}} + 3)));
+ foreach $r (@{$self->{'ATTACH'}{'POINTS'}})
+ {
+ push (@offs, $fh->tell() - $loc - $aoff);
+ $fh->print(pack('n*', $#{$r} + 1, @$r));
+ }
+ $coff = $fh->tell() - $loc - $aoff;
+ $self->{'ATTACH'}{'COVERAGE'}->out($fh);
+ $loc1 = $fh->tell();
+ $fh->seek($aoff + $loc, 0);
+ $fh->print(pack('n*', $coff, $#offs + 1, @offs));
+ $fh->seek($loc1, 0);
+ }
+
+ if (defined $self->{'LIG'})
+ {
+ my (@reftables, $ltables, $i, $j, $out, $r, $s);
+
+ $ltables = {};
+ $loff = $fh->tell() - $loc;
+ $out = pack('n*',
+ Font::TTF::Ttopen->ref_cache($self->{'LIG'}{'COVERAGE'}, $ltables, 0),
+ 0, $#{$self->{'LIG'}{'LIGS'}} + 1,
+ (0) x ($#{$self->{'LIG'}{'LIGS'}} + 1));
+ push (@reftables, [$ltables, 0]);
+ $i = 0;
+ foreach $r (@{$self->{'LIG'}{'LIGS'}})
+ {
+ $ltables = {};
+ $loc1 = length($out);
+ substr($out, ($i << 1) + 4, 2) = TTF_Pack('S', $loc1);
+ $out .= pack('n*', $#{$r} + 1, (0) x ($#{$r} + 1));
+ @offs = (); $j = 0;
+ foreach $s (@$r)
+ {
+ substr($out, ($j << 1) + 2 + $loc1, 2) =
+ TTF_Pack('S', length($out) - $loc1);
+ $out .= TTF_Pack('SS', $s->{'FMT'}, $s->{'VAL'});
+ $out .= pack('n', Font::TTF::Ttopen->ref_cache($s->{'DEVICE'},
+ $ltables, length($out))) if ($s->{'FMT'} == 3);
+ $j++;
+ }
+ push (@reftables, [$ltables, $loc1]);
+ $i++;
+ }
+ Font::TTF::Ttopen::out_final($fh, $out, \@reftables);
+ }
+
+ if ($new_gdef && defined $self->{'MARKS'})
+ {
+ $moff = $fh->tell() - $loc;
+ $self->{'MARKS'}->out($fh);
+ }
+
+ $loc1 = $fh->tell();
+ $fh->seek($loc + 4, 0);
+ if ($new_gdef)
+ { $fh->print(TTF_Pack('S4', $goff, $aoff, $loff, $moff)); }
+ else
+ { $fh->print(TTF_Pack('S3', $goff, $aoff, $loff)); }
+ $fh->seek($loc1, 0);
+ $self;
+}
+
+1;
+
Modified: packages/libfont-ttf-perl/trunk/lib/Font/TTF/GPOS.pm
===================================================================
--- packages/libfont-ttf-perl/trunk/lib/Font/TTF/GPOS.pm 2006-01-17 02:56:43 UTC (rev 1966)
+++ packages/libfont-ttf-perl/trunk/lib/Font/TTF/GPOS.pm 2006-01-17 03:07:20 UTC (rev 1967)
@@ -1,667 +1,667 @@
-package Font::TTF::GPOS;
-
-=head1 NAME
-
-Font::TTF::GPOS - Support for Opentype GPOS tables in conjunction with TTOpen
-
-=head1 DESCRIPTION
-
-The GPOS table is one of the most complicated tables in the TTF spec and the
-corresponding data structure abstraction is also not trivial. While much of the
-structure of a GPOS is shared with a GSUB table via the L<Font::TTF::Ttopen>
-
-=head1 INSTANCE VARIABLES
-
-Here we describe the additions and lookup specific information for GPOS tables.
-Unfortunately there is no one abstraction which seems to work comfortable for
-all GPOS tables, so we will also examine how the variables are used for different
-lookup types.
-
-The following are the values allowed in the ACTION_TYPE and MATCH_TYPE variables:
-
-=over 4
-
-=item ACTION_TYPE
-
-This can take any of the following values
-
-=over 8
-
-=item a
-
-The ACTION is an array of anchor tables
-
-=item o
-
-Offset. There is no RULE array. The ADJUST variable contains a value record (see
-later in this description)
-
-=item v
-
-The ACTION is a value record.
-
-=item p
-
-Pair adjustment. The ACTION contains an array of two value records for the matched
-two glyphs.
-
-=item e
-
-Exit and Entry records. The ACTION contains an array of two anchors corresponding
-to the exit and entry anchors for the glyph.
-
-=item l
-
-Indicates a lookup based contextual rule as per the GSUB table.
-
-=back
-
-=item MATCH_TYPE
-
-This can take any of the following values
-
-=over 8
-
-=item g
-
-A glyph array
-
-=item c
-
-An array of class values
-
-=item o
-
-An array of coverage tables
-
-=back
-
-=back
-
-The following variables are added for Attachment Positioning Subtables:
-
-=over 4
-
-=item MATCH
-
-This contains an array of glyphs to match against for all RULES. It is much like
-having the same MATCH string in all RULES. In the cases it is used so far, it only
-ever contains one element.
-
-=item MARKS
-
-This contains a Mark array consisting of each element being a subarray of two
-elements:
-
-=over 8
-
-=item CLASS
-
-The class that this mark uses on its base
-
-=item ANCHOR
-
-The anchor with which to attach this mark glyph
-
-=back
-
-The base table for mark to base, ligature or mark attachment positioning is
-structured with the ACTION containing an array of anchors corresponding to each
-attachment class. For ligatures, there is more than one RULE in the RULE array
-corresponding to each glyph in the coverage table.
-
-=back
-
-Other variables which are provided for informational purposes are:
-
-=over 4
-
-=item VFMT
-
-Value format for the adjustment of the glyph matched by the coverage table.
-
-=item VFMT2
-
-Value format used in pair adjustment for the second glyph in the pair
-
-=back
-
-=head2 Value Records
-
-There is a subtype used in GPOS tables called a value record. It is used to adjust
-the position of a glyph from its default position. The value record is variable
-length with a bitfield at the beginning to indicate which of the following
-entries are included. The bitfield is not stored since it is recalculated at
-write time.
-
-=over 4
-
-=item XPlacement
-
-Horizontal adjustment for placement (not affecting other unattached glyphs)
-
-=item YPlacement
-
-Vertical adjustment for placement (not affecting other unattached glyphs)
-
-=item XAdvance
-
-Adjust the advance width glyph (used only in horizontal writing systems)
-
-=item YAdvance
-
-Adjust the vertical advance (used only in vertical writing systems)
-
-=item XPlaDevice
-
-Device table for device specific adjustment of horizontal placement
-
-=item YPlaDevice
-
-Device table for device specific adjustment of vertical placement
-
-=item XAdvDevice
-
-Device table for device specific adjustment of horizontal advance
-
-=item YAdDevice
-
-Device table for device specific adjustment of vertical advance
-
-=item XIdPlacement
-
-Horizontal placement metric id (for Multiple Master fonts - but that's all I know!)
-
-=item YIdPlacement
-
-Vertical placement metric id
-
-=item XIdAdvance
-
-Horizontal advance metric id
-
-=item YIdAdvance
-
-Vertical advance metric id
-
-=back
-
-=head1 CORRESPONDANCE TO LAYOUT TYPES
-
-Here is what is stored in the ACTION_TYPE and MATCH_TYPE for each of the known
-GPOS subtable types:
-
- 1.1 1.2 2.1 2.2 3 4 5 6 7.1 7.2 7.3 8.1 8.2 8.3
- ACTION_TYPE o v p p e a a a l l l l l l
- MATCH_TYPE g c g c o g c o
-
-
-=head1 METHODS
-
-=cut
-
-use strict;
-use Font::TTF::Ttopen;
-use Font::TTF::Delta;
-use Font::TTF::Anchor;
-use Font::TTF::Utils;
-use vars qw(@ISA);
-
- at ISA = qw(Font::TTF::Ttopen);
-
-
-=head2 read_sub
-
-Reads the subtable into the data structures
-
-=cut
-
-sub read_sub
-{
- my ($self, $fh, $main_lookup, $sindex) = @_;
- my ($type) = $main_lookup->{'TYPE'};
- my ($loc) = $fh->tell();
- my ($lookup) = $main_lookup->{'SUB'}[$sindex];
- my ($dat, $mcount, $scount, $i, $j, $count, $fmt, $fmt2, $cover, $srec, $subst);
- my ($c1, $c2, $s, $moff, $boff);
-
-
- if ($type == 8)
- {
- $fh->read($dat, 4);
- ($fmt, $cover) = TTF_Unpack('S2', $dat);
- if ($fmt < 3)
- {
- $fh->read($dat, 2);
- $count = TTF_Unpack('S', $dat);
- }
- } else
- {
- $fh->read($dat, 6);
- ($fmt, $cover, $count) = TTF_Unpack("S3", $dat);
- }
- unless ($fmt == 3 && ($type == 7 || $type == 8))
- { $lookup->{'COVERAGE'} = $self->read_cover($cover, $loc, $lookup, $fh, 1); }
-
- $lookup->{'FORMAT'} = $fmt;
- if ($type == 1 && $fmt == 1)
- {
- $lookup->{'VFMT'} = $count;
- $lookup->{'ADJUST'} = $self->read_value($count, $loc, $lookup, $fh);
- $lookup->{'ACTION_TYPE'} = 'o';
- } elsif ($type == 1 && $fmt == 2)
- {
- $lookup->{'VFMT'} = $count;
- $fh->read($dat, 2);
- $mcount = unpack('n', $dat);
- for ($i = 0; $i < $mcount; $i++)
- { push (@{$lookup->{'RULES'}}, [{'ACTION'} =>
- [$self->read_value($count, $loc, $lookup, $fh)]]); }
- $self->{'ACTION_TYPE'} = 'v';
- } elsif ($type == 2 && $fmt == 1)
- {
- $lookup->{'VFMT'} = $count;
- $fh->read($dat, 4);
- ($fmt2, $mcount) = unpack('n2', $dat);
- $lookup->{'VFMT2'} = $fmt2;
- $fh->read($dat, $mcount << 1);
- foreach $s (unpack('n*', $dat))
- {
- $fh->seek($loc + $s, 0);
- $fh->read($dat, 2);
- $scount = TTF_Unpack('S', $dat);
- $subst = [];
- for ($i = 0; $i < $scount; $i++)
- {
- $srec = {};
- $fh->read($dat, 2);
- $srec->{'MATCH'} = [TTF_Unpack('S', $dat)];
- $srec->{'ACTION'} = [$self->read_value($count, $loc, $lookup, $fh),
- $self->read_value($fmt2, $loc, $lookup, $fh)];
- push (@$subst, $srec);
- }
- push (@{$lookup->{'RULES'}}, $subst);
- }
- $lookup->{'ACTION_TYPE'} = 'p';
- $lookup->{'MATCH_TYPE'} = 'g';
- } elsif ($type == 2 && $fmt == 2)
- {
- $fh->read($dat, 10);
- ($lookup->{'VFMT2'}, $c1, $c2, $mcount, $scount) = TTF_Unpack('S*', $dat);
- $lookup->{'CLASS'} = $self->read_cover($c1, $loc, $lookup, $fh, 0);
- $lookup->{'MATCH'} = [$self->read_cover($c2, $loc, $lookup, $fh, 0)];
- $lookup->{'VFMT'} = $count;
- for ($i = 0; $i < $mcount; $i++)
- {
- $subst = [];
- for ($j = 0; $j < $scount; $j++)
- {
- $srec = {};
- $srec->{'ACTION'} = [$self->read_value($lookup->{'VFMT'}, $loc, $lookup, $fh),
- $self->read_value($lookup->{'VFMT2'}, $loc, $lookup, $fh)];
- push (@$subst, $srec);
- }
- push (@{$lookup->{'RULES'}}, $subst);
- }
- $lookup->{'ACTION_TYPE'} = 'p';
- $lookup->{'MATCH_TYPE'} = 'c';
- } elsif ($type == 3 && $fmt == 1)
- {
- $fh->read($dat, $count << 2);
- for ($i = 0; $i < $count; $i++)
- { push (@{$lookup->{'RULES'}}, [{'ACTION' =>
- [$self->read_anchor(TTF_Unpack('S', substr($dat, $i << 2, 2)),
- $loc, $lookup, $fh),
- $self->read_anchor(TTF_Unpack('S', substr($dat, ($i << 2) + 2, 2)),
- $loc, $lookup, $fh)]}]); }
- $lookup->{'ACTION_TYPE'} = 'e';
- } elsif ($type == 4 || $type == 5 || $type == 6)
- {
- my (@offs, $mloc, $thisloc, $ncomp, $k);
-
- $lookup->{'MATCH'} = [$lookup->{'COVERAGE'}];
- $lookup->{'COVERAGE'} = $self->read_cover($count, $loc, $lookup, $fh, 1);
- $fh->read($dat, 6);
- ($mcount, $moff, $boff) = TTF_Unpack('S*', $dat);
- $fh->seek($loc + $moff, 0);
- $fh->read($dat, 2);
- $count = TTF_Unpack('S', $dat);
- for ($i = 0; $i < $count; $i++)
- {
- $fh->read($dat, 4);
- push (@{$lookup->{'MARKS'}}, [TTF_Unpack('S', $dat),
- $self->read_anchor(TTF_Unpack('S', substr($dat, 2, 2)) + $moff,
- $loc, $lookup, $fh)]);
- }
- $fh->seek($loc + $boff, 0);
- $fh->read($dat, 2);
- $count = TTF_Unpack('S', $dat);
- $mloc = $fh->tell() - 2;
- $thisloc = $mloc;
- if ($type == 5)
- {
- $fh->read($dat, $count << 1);
- @offs = TTF_Unpack('S*', $dat);
- }
- for ($i = 0; $i < $count; $i++)
- {
- if ($type == 5)
- {
- $thisloc = $mloc + $offs[$i];
- $fh->seek($thisloc, 0);
- $fh->read($dat, 2);
- $ncomp = TTF_Unpack('S', $dat);
- } else
- { $ncomp = 1; }
- for ($j = 0; $j < $ncomp; $j++)
- {
- $subst = [];
- $fh->read($dat, $mcount << 1);
- for ($k = 0; $k < $mcount; $k++)
- { push (@$subst, $self->read_anchor(TTF_Unpack('S', substr($dat, $k << 1, 2)) + $thisloc - $loc,
- $loc, $lookup, $fh)); }
-
- push (@{$lookup->{'RULES'}[$i]}, {'ACTION' => $subst});
- }
- }
- $lookup->{'ACTION_TYPE'} = 'a';
- } elsif ($type == 7 || $type == 8)
- { $self->read_context($lookup, $fh, $type - 2, $fmt, $cover, $count, $loc); }
- $lookup;
-}
-
-
-=head2 $t->extension
-
-Returns the table type number for the extension table
-
-=cut
-
-sub extension
-{ return 9; }
-
-
-=head2 $t->out_sub
-
-Outputs the subtable to the given filehandle
-
-=cut
-
-sub out_sub
-{
- my ($self, $fh, $main_lookup, $index) = @_;
- my ($type) = $main_lookup->{'TYPE'};
- my ($lookup) = $main_lookup->{'SUB'}[$index];
- my ($fmt) = $lookup->{'FORMAT'};
- my ($out, $r, $s, $t, $i, $j, $vfmt, $vfmt2, $loc1);
- my ($num) = $#{$lookup->{'RULES'}} + 1;
- my ($ctables) = {};
- my ($mtables) = {};
- my (@reftables);
-
- if ($type == 1 && $fmt == 1)
- {
- $out = pack('n2', $fmt, Font::TTF::Ttopen::ref_cache($lookup->{'COVERAGE'}, $ctables, 2));
- $vfmt = $self->fmt_value($lookup->{'ADJUST'});
- $out .= pack('n', $vfmt) . $self->out_value($lookup->{'ADJUST'}, $vfmt, $ctables, 6);
- } elsif ($type == 1 && $fmt == 2)
- {
- $vfmt = 0;
- foreach $r (@{$lookup->{'RULES'}})
- { $vfmt |= $self->fmt_value($r->[0]{'ACTION'}[0]); }
- $out = pack('n4', $fmt, Font::TTF::Ttopen::ref_cache($lookup->{'COVERAGE'}, $ctables, 2),
- $vfmt, $#{$lookup->{'RULES'}} + 1);
- foreach $r (@{$lookup->{'RULES'}})
- { $out .= $self->out_value($r->[0]{'ACTION'}[0], $vfmt, $ctables, length($out)); }
- } elsif ($type == 2 && $fmt < 3)
- {
- $vfmt = 0;
- $vfmt2 = 0;
- foreach $r (@{$lookup->{'RULES'}})
- {
- foreach $t (@$r)
- {
- $vfmt |= $self->fmt_value($t->{'ACTION'}[0]);
- $vfmt2 |= $self->fmt_value($t->{'ACTION'}[1]);
- }
- }
- if ($fmt == 1)
- {
- $out = pack('n5', $fmt, Font::TTF::Ttopen::ref_cache($lookup->{'COVERAGE'}, $ctables, 2),
- $vfmt, $vfmt2, $#{$lookup->{'RULES'}} + 1);
- } else
- {
- $out = pack('n8', $fmt, Font::TTF::Ttopen::ref_cache($lookup->{'COVERAGE'}, $ctables, 2),
- $vfmt, $vfmt2,
- Font::TTF::Ttopen::ref_cache($lookup->{'CLASS'}, $ctables, 1),
- Font::TTF::Ttopen::ref_cache($lookup->{'MATCH'}[0], $ctables, 1),
- $#{$lookup->{'RULES'}} + 1, $#{$lookup->{'RULES'}[0]} + 1);
- }
- foreach $r (@{$lookup->{'RULES'}})
- {
- $out .= $#{$r} + 1 if ($fmt == 1);
- foreach $t (@$r)
- {
- $out .= pack('n', $t->{'MATCH'}[0]) if ($fmt == 1);
- $out .= $self->out_value($t->{'ACTION'}[0], $vfmt, $ctables, length($out))
- . $self->out_value($t->{'ACTION'}[1], $vfmt2, $ctables, length($out) + 2);
- }
- }
- } elsif ($type == 3 && $fmt == 1)
- {
- $out = pack('n3', $fmt, Font::TTF::Ttopen::ref_cache($lookup->{'COVERAGE'}, $ctables, 2),
- $#{$lookup->{'RULES'}} + 1);
- foreach $r (@{$lookup->{'RULES'}})
- {
- $out .= pack('n2', Font::TTF::Ttopen::ref_cache($r->[0]{'ACTION'}[0], $ctables, length($out)),
- Font::TTF::Ttopen::ref_cache($r->[0]{'ACTION'}[1], $ctables, length($out) + 2));
- }
- } elsif ($type == 4 || $type == 5 || $type == 6)
- {
- my ($loc_off, $loc_t, $ltables);
-
- $out = pack('n7', $fmt, Font::TTF::Ttopen::ref_cache($lookup->{'MATCH'}[0], $ctables, 2),
- Font::TTF::Ttopen::ref_cache($lookup->{'COVERAGE'}, $ctables, 4),
- $#{$lookup->{'RULES'}[0][0]{'ACTION'}} + 1, 12, ($#{$lookup->{'MARKS'}} + 4) << 2,
- $#{$lookup->{'MARKS'}} + 1);
- foreach $r (@{$lookup->{'MARKS'}})
- { $out .= pack('n2', $r->[0], Font::TTF::Ttopen::ref_cache($r->[1], $mtables, length($out) + 2)); }
- push (@reftables, [$mtables, 12]);
-
- $loc_t = length($out);
- substr($out, 10, 2) = pack('n', $loc_t);
- $out .= pack('n', $#{$lookup->{'RULES'}} + 1);
- if ($type == 5)
- {
- $loc1 = length($out);
- $out .= pack('n*', (0) x ($#{$lookup->{'RULES'}} + 1));
- }
- $ltables = {};
- for ($i = 0; $i <= $#{$lookup->{'RULES'}}; $i++)
- {
- if ($type == 5)
- {
- $ltables = {};
- $loc_t = length($out);
- substr($out, $loc1 + ($i << 1), 2) = TTF_Pack('S', $loc_t - $loc1 + 2);
- }
-
- $r = $lookup->{'RULES'}[$i];
- $out .= pack('n', $#{$r} + 1) if ($type == 5);
- foreach $t (@$r)
- {
- foreach $s (@{$t->{'ACTION'}})
- { $out .= pack('n', Font::TTF::Ttopen::ref_cache($s, $ltables, length($out))); }
- }
- push (@reftables, [$ltables, $loc_t]) if ($type == 5);
- }
- push (@reftables, [$ltables, $loc_t]) unless ($type == 5);
- } elsif ($type == 7 || $type == 8)
- { $out = $self->out_context($lookup, $fh, $type - 2, $fmt, $ctables, $out, $num); }
- push (@reftables, [$ctables, 0]);
- Font::TTF::Ttopen::out_final($fh, $out, \@reftables);
- $lookup;
-}
-
-
-=head2 $t->read_value($format, $base, $lookup, $fh)
-
-Reads a value record from the current location in the file, according to the
-format given.
-
-=cut
-
-sub read_value
-{
- my ($self, $fmt, $base, $lookup, $fh) = @_;
- my ($flag) = 1;
- my ($res) = {};
- my ($s, $i, $dat);
-
- $s = 0;
- for ($i = 0; $i < 12; $i++)
- {
- $s++ if ($flag & $fmt);
- $flag <<= 1;
- }
-
- $fh->read($dat, $s << 1);
- $flag = 1; $i = 0;
- foreach $s (qw(XPlacement YPlacement XAdvance YAdvance))
- {
- $res->{$s} = TTF_Unpack('s', substr($dat, $i++ << 1, 2)) if ($fmt & $flag);
- $flag <<= 1;
- }
-
- foreach $s (qw(XPlaDevice YPlaDevice XAdvDevice YAdvDevice))
- {
- if ($fmt & $flag)
- { $res->{$s} = $self->read_delta(TTF_Unpack('S', substr($i++ << 1, 2)),
- $base, $lookup, $fh); }
- $flag <<= 1;
- }
-
- foreach $s (qw(XIdPlacement YIdPlacement XIdAdvance YIdAdvance))
- {
- $res->{$s} = TTF_Unpack('S', substr($dat, $i++ << 1, 2)) if ($fmt & $flag);
- $flag <<= 1;
- }
- $res;
-}
-
-
-=head2 $t->read_delta($offset, $base, $lookup, $fh)
-
-Reads a delta (device table) at the given offset if it hasn't already been read.
-Store the offset and item in the lookup cache ($lookup->{' CACHE'})
-
-=cut
-
-sub read_delta
-{
- my ($self, $offset, $base, $lookup, $fh) = @_;
- my ($loc) = $fh->tell();
- my ($res, $str);
-
- return undef unless $offset;
- $str = sprintf("%X", $base + $offset);
- return $lookup->{' CACHE'}{$str} if defined $lookup->{' CACHE'}{$str};
- $fh->seek($base + $offset, 0);
- $res = Font::TTF::Delta->new->read($fh);
- $fh->seek($loc, 0);
- $lookup->{' CACHE'}{$str} = $res;
- return $res;
-}
-
-
-=head2 $t->read_anchor($offset, $base, $lookup, $fh)
-
-Reads an Anchor table at the given offset if it hasn't already been read.
-
-=cut
-
-sub read_anchor
-{
- my ($self, $offset, $base, $lookup, $fh) = @_;
- my ($loc) = $fh->tell();
- my ($res, $str);
-
- return undef unless $offset;
- $str = sprintf("%X", $base + $offset);
- return $lookup->{' CACHE'}{$str} if defined $lookup->{' CACHE'}{$str};
- $fh->seek($base + $offset, 0);
- $res = Font::TTF::Anchor->new->read($fh);
- $fh->seek($loc, 0);
- $lookup->{' CACHE'}{$str} = $res;
- return $res;
-}
-
-
-=head2 $t->fmt_value
-
-Returns the value format for a given value record
-
-=cut
-
-sub fmt_value
-{
- my ($self, $value) = @_;
- my ($fmt) = 0;
- my ($n);
-
- foreach $n (reverse qw(XPlacement YPlacement XAdvance YAdvance XPlaDevice YPlaDevice
- XAdvDevice YAdvDevice XIdPlacement YIdPlacement XIdAdvance
- YIdAdvance))
- {
- $fmt <<= 1;
- $fmt |= 1 if (defined $value->{$n} && (ref $value->{$n} || $value->{$n}));
- }
- $fmt;
-}
-
-
-=head2 $t->out_value
-
-Returns the output string for the outputting of the value for a given format. Also
-updates the offset cache for any device tables referenced.
-
-=cut
-
-sub out_value
-{
- my ($self, $value, $fmt, $tables, $offset) = @_;
- my ($n, $flag, $out);
-
- $flag = 1;
- foreach $n (qw(XPlacement YPlacement XAdvance YAdvance))
- {
- $out .= pack('n', $value->{$n}) if ($flag & $fmt);
- $flag <<= 1;
- }
- foreach $n (qw(XPlaDevice YPlaDevice XAdvDevice YAdvDevice))
- {
- if ($flag & $fmt)
- {
- $out .= pack('n', Font::TTF::Ttopen::ref_cache(
- $value->{$n}, $tables, $offset + length($out)));
- }
- $flag <<= 1;
- }
- foreach $n (qw(XIdPlacement YIdPlacement XIdAdvance YIdAdvance))
- {
- $out .= pack('n', $value->{$n}) if ($flag & $fmt);
- $flag <<= 1;
- }
- $out;
-}
-
-
-=head1 AUTHOR
-
-Martin Hosken Martin_Hosken at sil.org. See L<Font::TTF::Font> for copyright and
-licensing.
-
-=cut
-
-1;
-
+package Font::TTF::GPOS;
+
+=head1 TITLE
+
+Font::TTF::GPOS - Support for Opentype GPOS tables in conjunction with TTOpen
+
+=head1 DESCRIPTION
+
+The GPOS table is one of the most complicated tables in the TTF spec and the
+corresponding data structure abstraction is also not trivial. While much of the
+structure of a GPOS is shared with a GSUB table via the L<Font::TTF::Ttopen>
+
+=head1 INSTANCE VARIABLES
+
+Here we describe the additions and lookup specific information for GPOS tables.
+Unfortunately there is no one abstraction which seems to work comfortable for
+all GPOS tables, so we will also examine how the variables are used for different
+lookup types.
+
+The following are the values allowed in the ACTION_TYPE and MATCH_TYPE variables:
+
+=over 4
+
+=item ACTION_TYPE
+
+This can take any of the following values
+
+=over 8
+
+=item a
+
+The ACTION is an array of anchor tables
+
+=item o
+
+Offset. There is no RULE array. The ADJUST variable contains a value record (see
+later in this description)
+
+=item v
+
+The ACTION is a value record.
+
+=item p
+
+Pair adjustment. The ACTION contains an array of two value records for the matched
+two glyphs.
+
+=item e
+
+Exit and Entry records. The ACTION contains an array of two anchors corresponding
+to the exit and entry anchors for the glyph.
+
+=item l
+
+Indicates a lookup based contextual rule as per the GSUB table.
+
+=back
+
+=item MATCH_TYPE
+
+This can take any of the following values
+
+=over 8
+
+=item g
+
+A glyph array
+
+=item c
+
+An array of class values
+
+=item o
+
+An array of coverage tables
+
+=back
+
+=back
+
+The following variables are added for Attachment Positioning Subtables:
+
+=over 4
+
+=item MATCH
+
+This contains an array of glyphs to match against for all RULES. It is much like
+having the same MATCH string in all RULES. In the cases it is used so far, it only
+ever contains one element.
+
+=item MARKS
+
+This contains a Mark array consisting of each element being a subarray of two
+elements:
+
+=over 8
+
+=item CLASS
+
+The class that this mark uses on its base
+
+=item ANCHOR
+
+The anchor with which to attach this mark glyph
+
+=back
+
+The base table for mark to base, ligature or mark attachment positioning is
+structured with the ACTION containing an array of anchors corresponding to each
+attachment class. For ligatures, there is more than one RULE in the RULE array
+corresponding to each glyph in the coverage table.
+
+=back
+
+Other variables which are provided for informational purposes are:
+
+=over 4
+
+=item VFMT
+
+Value format for the adjustment of the glyph matched by the coverage table.
+
+=item VFMT2
+
+Value format used in pair adjustment for the second glyph in the pair
+
+=back
+
+=head2 Value Records
+
+There is a subtype used in GPOS tables called a value record. It is used to adjust
+the position of a glyph from its default position. The value record is variable
+length with a bitfield at the beginning to indicate which of the following
+entries are included. The bitfield is not stored since it is recalculated at
+write time.
+
+=over 4
+
+=item XPlacement
+
+Horizontal adjustment for placement (not affecting other unattached glyphs)
+
+=item YPlacement
+
+Vertical adjustment for placement (not affecting other unattached glyphs)
+
+=item XAdvance
+
+Adjust the advance width glyph (used only in horizontal writing systems)
+
+=item YAdvance
+
+Adjust the vertical advance (used only in vertical writing systems)
+
+=item XPlaDevice
+
+Device table for device specific adjustment of horizontal placement
+
+=item YPlaDevice
+
+Device table for device specific adjustment of vertical placement
+
+=item XAdvDevice
+
+Device table for device specific adjustment of horizontal advance
+
+=item YAdDevice
+
+Device table for device specific adjustment of vertical advance
+
+=item XIdPlacement
+
+Horizontal placement metric id (for Multiple Master fonts - but that's all I know!)
+
+=item YIdPlacement
+
+Vertical placement metric id
+
+=item XIdAdvance
+
+Horizontal advance metric id
+
+=item YIdAdvance
+
+Vertical advance metric id
+
+=back
+
+=head1 CORRESPONDANCE TO LAYOUT TYPES
+
+Here is what is stored in the ACTION_TYPE and MATCH_TYPE for each of the known
+GPOS subtable types:
+
+ 1.1 1.2 2.1 2.2 3 4 5 6 7.1 7.2 7.3 8.1 8.2 8.3
+ ACTION_TYPE o v p p e a a a l l l l l l
+ MATCH_TYPE g c g c o g c o
+
+
+=head1 METHODS
+
+=cut
+
+use strict;
+use Font::TTF::Ttopen;
+use Font::TTF::Delta;
+use Font::TTF::Anchor;
+use Font::TTF::Utils;
+use vars qw(@ISA);
+
+ at ISA = qw(Font::TTF::Ttopen);
+
+
+=head2 read_sub
+
+Reads the subtable into the data structures
+
+=cut
+
+sub read_sub
+{
+ my ($self, $fh, $main_lookup, $sindex) = @_;
+ my ($type) = $main_lookup->{'TYPE'};
+ my ($loc) = $fh->tell();
+ my ($lookup) = $main_lookup->{'SUB'}[$sindex];
+ my ($dat, $mcount, $scount, $i, $j, $count, $fmt, $fmt2, $cover, $srec, $subst);
+ my ($c1, $c2, $s, $moff, $boff);
+
+
+ if ($type == 8)
+ {
+ $fh->read($dat, 4);
+ ($fmt, $cover) = TTF_Unpack('S2', $dat);
+ if ($fmt < 3)
+ {
+ $fh->read($dat, 2);
+ $count = TTF_Unpack('S', $dat);
+ }
+ } else
+ {
+ $fh->read($dat, 6);
+ ($fmt, $cover, $count) = TTF_Unpack("S3", $dat);
+ }
+ unless ($fmt == 3 && ($type == 7 || $type == 8))
+ { $lookup->{'COVERAGE'} = $self->read_cover($cover, $loc, $lookup, $fh, 1); }
+
+ $lookup->{'FORMAT'} = $fmt;
+ if ($type == 1 && $fmt == 1)
+ {
+ $lookup->{'VFMT'} = $count;
+ $lookup->{'ADJUST'} = $self->read_value($count, $loc, $lookup, $fh);
+ $lookup->{'ACTION_TYPE'} = 'o';
+ } elsif ($type == 1 && $fmt == 2)
+ {
+ $lookup->{'VFMT'} = $count;
+ $fh->read($dat, 2);
+ $mcount = unpack('n', $dat);
+ for ($i = 0; $i < $mcount; $i++)
+ { push (@{$lookup->{'RULES'}}, [{'ACTION'} =>
+ [$self->read_value($count, $loc, $lookup, $fh)]]); }
+ $self->{'ACTION_TYPE'} = 'v';
+ } elsif ($type == 2 && $fmt == 1)
+ {
+ $lookup->{'VFMT'} = $count;
+ $fh->read($dat, 4);
+ ($fmt2, $mcount) = unpack('n2', $dat);
+ $lookup->{'VFMT2'} = $fmt2;
+ $fh->read($dat, $mcount << 1);
+ foreach $s (unpack('n*', $dat))
+ {
+ $fh->seek($loc + $s, 0);
+ $fh->read($dat, 2);
+ $scount = TTF_Unpack('S', $dat);
+ $subst = [];
+ for ($i = 0; $i < $scount; $i++)
+ {
+ $srec = {};
+ $fh->read($dat, 2);
+ $srec->{'MATCH'} = [TTF_Unpack('S', $dat)];
+ $srec->{'ACTION'} = [$self->read_value($count, $loc, $lookup, $fh),
+ $self->read_value($fmt2, $loc, $lookup, $fh)];
+ push (@$subst, $srec);
+ }
+ push (@{$lookup->{'RULES'}}, $subst);
+ }
+ $lookup->{'ACTION_TYPE'} = 'p';
+ $lookup->{'MATCH_TYPE'} = 'g';
+ } elsif ($type == 2 && $fmt == 2)
+ {
+ $fh->read($dat, 10);
+ ($lookup->{'VFMT2'}, $c1, $c2, $mcount, $scount) = TTF_Unpack('S*', $dat);
+ $lookup->{'CLASS'} = $self->read_cover($c1, $loc, $lookup, $fh, 0);
+ $lookup->{'MATCH'} = [$self->read_cover($c2, $loc, $lookup, $fh, 0)];
+ $lookup->{'VFMT'} = $count;
+ for ($i = 0; $i < $mcount; $i++)
+ {
+ $subst = [];
+ for ($j = 0; $j < $scount; $j++)
+ {
+ $srec = {};
+ $srec->{'ACTION'} = [$self->read_value($lookup->{'VFMT'}, $loc, $lookup, $fh),
+ $self->read_value($lookup->{'VFMT2'}, $loc, $lookup, $fh)];
+ push (@$subst, $srec);
+ }
+ push (@{$lookup->{'RULES'}}, $subst);
+ }
+ $lookup->{'ACTION_TYPE'} = 'p';
+ $lookup->{'MATCH_TYPE'} = 'c';
+ } elsif ($type == 3 && $fmt == 1)
+ {
+ $fh->read($dat, $count << 2);
+ for ($i = 0; $i < $count; $i++)
+ { push (@{$lookup->{'RULES'}}, [{'ACTION' =>
+ [$self->read_anchor(TTF_Unpack('S', substr($dat, $i << 2, 2)),
+ $loc, $lookup, $fh),
+ $self->read_anchor(TTF_Unpack('S', substr($dat, ($i << 2) + 2, 2)),
+ $loc, $lookup, $fh)]}]); }
+ $lookup->{'ACTION_TYPE'} = 'e';
+ } elsif ($type == 4 || $type == 5 || $type == 6)
+ {
+ my (@offs, $mloc, $thisloc, $ncomp, $k);
+
+ $lookup->{'MATCH'} = [$lookup->{'COVERAGE'}];
+ $lookup->{'COVERAGE'} = $self->read_cover($count, $loc, $lookup, $fh, 1);
+ $fh->read($dat, 6);
+ ($mcount, $moff, $boff) = TTF_Unpack('S*', $dat);
+ $fh->seek($loc + $moff, 0);
+ $fh->read($dat, 2);
+ $count = TTF_Unpack('S', $dat);
+ for ($i = 0; $i < $count; $i++)
+ {
+ $fh->read($dat, 4);
+ push (@{$lookup->{'MARKS'}}, [TTF_Unpack('S', $dat),
+ $self->read_anchor(TTF_Unpack('S', substr($dat, 2, 2)) + $moff,
+ $loc, $lookup, $fh)]);
+ }
+ $fh->seek($loc + $boff, 0);
+ $fh->read($dat, 2);
+ $count = TTF_Unpack('S', $dat);
+ $mloc = $fh->tell() - 2;
+ $thisloc = $mloc;
+ if ($type == 5)
+ {
+ $fh->read($dat, $count << 1);
+ @offs = TTF_Unpack('S*', $dat);
+ }
+ for ($i = 0; $i < $count; $i++)
+ {
+ if ($type == 5)
+ {
+ $thisloc = $mloc + $offs[$i];
+ $fh->seek($thisloc, 0);
+ $fh->read($dat, 2);
+ $ncomp = TTF_Unpack('S', $dat);
+ } else
+ { $ncomp = 1; }
+ for ($j = 0; $j < $ncomp; $j++)
+ {
+ $subst = [];
+ $fh->read($dat, $mcount << 1);
+ for ($k = 0; $k < $mcount; $k++)
+ { push (@$subst, $self->read_anchor(TTF_Unpack('S', substr($dat, $k << 1, 2)) + $thisloc - $loc,
+ $loc, $lookup, $fh)); }
+
+ push (@{$lookup->{'RULES'}[$i]}, {'ACTION' => $subst});
+ }
+ }
+ $lookup->{'ACTION_TYPE'} = 'a';
+ } elsif ($type == 7 || $type == 8)
+ { $self->read_context($lookup, $fh, $type - 2, $fmt, $cover, $count, $loc); }
+ $lookup;
+}
+
+
+=head2 $t->extension
+
+Returns the table type number for the extension table
+
+=cut
+
+sub extension
+{ return 9; }
+
+
+=head2 $t->out_sub
+
+Outputs the subtable to the given filehandle
+
+=cut
+
+sub out_sub
+{
+ my ($self, $fh, $main_lookup, $index) = @_;
+ my ($type) = $main_lookup->{'TYPE'};
+ my ($lookup) = $main_lookup->{'SUB'}[$index];
+ my ($fmt) = $lookup->{'FORMAT'};
+ my ($out, $r, $s, $t, $i, $j, $vfmt, $vfmt2, $loc1);
+ my ($num) = $#{$lookup->{'RULES'}} + 1;
+ my ($ctables) = {};
+ my ($mtables) = {};
+ my (@reftables);
+
+ if ($type == 1 && $fmt == 1)
+ {
+ $out = pack('n2', $fmt, Font::TTF::Ttopen::ref_cache($lookup->{'COVERAGE'}, $ctables, 2));
+ $vfmt = $self->fmt_value($lookup->{'ADJUST'});
+ $out .= pack('n', $vfmt) . $self->out_value($lookup->{'ADJUST'}, $vfmt, $ctables, 6);
+ } elsif ($type == 1 && $fmt == 2)
+ {
+ $vfmt = 0;
+ foreach $r (@{$lookup->{'RULES'}})
+ { $vfmt |= $self->fmt_value($r->[0]{'ACTION'}[0]); }
+ $out = pack('n4', $fmt, Font::TTF::Ttopen::ref_cache($lookup->{'COVERAGE'}, $ctables, 2),
+ $vfmt, $#{$lookup->{'RULES'}} + 1);
+ foreach $r (@{$lookup->{'RULES'}})
+ { $out .= $self->out_value($r->[0]{'ACTION'}[0], $vfmt, $ctables, length($out)); }
+ } elsif ($type == 2 && $fmt < 3)
+ {
+ $vfmt = 0;
+ $vfmt2 = 0;
+ foreach $r (@{$lookup->{'RULES'}})
+ {
+ foreach $t (@$r)
+ {
+ $vfmt |= $self->fmt_value($t->{'ACTION'}[0]);
+ $vfmt2 |= $self->fmt_value($t->{'ACTION'}[1]);
+ }
+ }
+ if ($fmt == 1)
+ {
+ $out = pack('n5', $fmt, Font::TTF::Ttopen::ref_cache($lookup->{'COVERAGE'}, $ctables, 2),
+ $vfmt, $vfmt2, $#{$lookup->{'RULES'}} + 1);
+ } else
+ {
+ $out = pack('n8', $fmt, Font::TTF::Ttopen::ref_cache($lookup->{'COVERAGE'}, $ctables, 2),
+ $vfmt, $vfmt2,
+ Font::TTF::Ttopen::ref_cache($lookup->{'CLASS'}, $ctables, 1),
+ Font::TTF::Ttopen::ref_cache($lookup->{'MATCH'}[0], $ctables, 1),
+ $#{$lookup->{'RULES'}} + 1, $#{$lookup->{'RULES'}[0]} + 1);
+ }
+ foreach $r (@{$lookup->{'RULES'}})
+ {
+ $out .= $#{$r} + 1 if ($fmt == 1);
+ foreach $t (@$r)
+ {
+ $out .= pack('n', $t->{'MATCH'}[0]) if ($fmt == 1);
+ $out .= $self->out_value($t->{'ACTION'}[0], $vfmt, $ctables, length($out))
+ . $self->out_value($t->{'ACTION'}[1], $vfmt2, $ctables, length($out) + 2);
+ }
+ }
+ } elsif ($type == 3 && $fmt == 1)
+ {
+ $out = pack('n3', $fmt, Font::TTF::Ttopen::ref_cache($lookup->{'COVERAGE'}, $ctables, 2),
+ $#{$lookup->{'RULES'}} + 1);
+ foreach $r (@{$lookup->{'RULES'}})
+ {
+ $out .= pack('n2', Font::TTF::Ttopen::ref_cache($r->[0]{'ACTION'}[0], $ctables, length($out)),
+ Font::TTF::Ttopen::ref_cache($r->[0]{'ACTION'}[1], $ctables, length($out) + 2));
+ }
+ } elsif ($type == 4 || $type == 5 || $type == 6)
+ {
+ my ($loc_off, $loc_t, $ltables);
+
+ $out = pack('n7', $fmt, Font::TTF::Ttopen::ref_cache($lookup->{'MATCH'}[0], $ctables, 2),
+ Font::TTF::Ttopen::ref_cache($lookup->{'COVERAGE'}, $ctables, 4),
+ $#{$lookup->{'RULES'}[0][0]{'ACTION'}} + 1, 12, ($#{$lookup->{'MARKS'}} + 4) << 2,
+ $#{$lookup->{'MARKS'}} + 1);
+ foreach $r (@{$lookup->{'MARKS'}})
+ { $out .= pack('n2', $r->[0], Font::TTF::Ttopen::ref_cache($r->[1], $mtables, length($out) + 2)); }
+ push (@reftables, [$mtables, 12]);
+
+ $loc_t = length($out);
+ substr($out, 10, 2) = pack('n', $loc_t);
+ $out .= pack('n', $#{$lookup->{'RULES'}} + 1);
+ if ($type == 5)
+ {
+ $loc1 = length($out);
+ $out .= pack('n*', (0) x ($#{$lookup->{'RULES'}} + 1));
+ }
+ $ltables = {};
+ for ($i = 0; $i <= $#{$lookup->{'RULES'}}; $i++)
+ {
+ if ($type == 5)
+ {
+ $ltables = {};
+ $loc_t = length($out);
+ substr($out, $loc1 + ($i << 1), 2) = TTF_Pack('S', $loc_t - $loc1 + 2);
+ }
+
+ $r = $lookup->{'RULES'}[$i];
+ $out .= pack('n', $#{$r} + 1) if ($type == 5);
+ foreach $t (@$r)
+ {
+ foreach $s (@{$t->{'ACTION'}})
+ { $out .= pack('n', Font::TTF::Ttopen::ref_cache($s, $ltables, length($out))); }
+ }
+ push (@reftables, [$ltables, $loc_t]) if ($type == 5);
+ }
+ push (@reftables, [$ltables, $loc_t]) unless ($type == 5);
+ } elsif ($type == 7 || $type == 8)
+ { $out = $self->out_context($lookup, $fh, $type - 2, $fmt, $ctables, $out, $num); }
+ push (@reftables, [$ctables, 0]);
+ Font::TTF::Ttopen::out_final($fh, $out, \@reftables);
+ $lookup;
+}
+
+
+=head2 $t->read_value($format, $base, $lookup, $fh)
+
+Reads a value record from the current location in the file, according to the
+format given.
+
+=cut
+
+sub read_value
+{
+ my ($self, $fmt, $base, $lookup, $fh) = @_;
+ my ($flag) = 1;
+ my ($res) = {};
+ my ($s, $i, $dat);
+
+ $s = 0;
+ for ($i = 0; $i < 12; $i++)
+ {
+ $s++ if ($flag & $fmt);
+ $flag <<= 1;
+ }
+
+ $fh->read($dat, $s << 1);
+ $flag = 1; $i = 0;
+ foreach $s (qw(XPlacement YPlacement XAdvance YAdvance))
+ {
+ $res->{$s} = TTF_Unpack('s', substr($dat, $i++ << 1, 2)) if ($fmt & $flag);
+ $flag <<= 1;
+ }
+
+ foreach $s (qw(XPlaDevice YPlaDevice XAdvDevice YAdvDevice))
+ {
+ if ($fmt & $flag)
+ { $res->{$s} = $self->read_delta(TTF_Unpack('S', substr($i++ << 1, 2)),
+ $base, $lookup, $fh); }
+ $flag <<= 1;
+ }
+
+ foreach $s (qw(XIdPlacement YIdPlacement XIdAdvance YIdAdvance))
+ {
+ $res->{$s} = TTF_Unpack('S', substr($dat, $i++ << 1, 2)) if ($fmt & $flag);
+ $flag <<= 1;
+ }
+ $res;
+}
+
+
+=head2 $t->read_delta($offset, $base, $lookup, $fh)
+
+Reads a delta (device table) at the given offset if it hasn't already been read.
+Store the offset and item in the lookup cache ($lookup->{' CACHE'})
+
+=cut
+
+sub read_delta
+{
+ my ($self, $offset, $base, $lookup, $fh) = @_;
+ my ($loc) = $fh->tell();
+ my ($res, $str);
+
+ return undef unless $offset;
+ $str = sprintf("%X", $base + $offset);
+ return $lookup->{' CACHE'}{$str} if defined $lookup->{' CACHE'}{$str};
+ $fh->seek($base + $offset, 0);
+ $res = Font::TTF::Delta->new->read($fh);
+ $fh->seek($loc, 0);
+ $lookup->{' CACHE'}{$str} = $res;
+ return $res;
+}
+
+
+=head2 $t->read_anchor($offset, $base, $lookup, $fh)
+
+Reads an Anchor table at the given offset if it hasn't already been read.
+
+=cut
+
+sub read_anchor
+{
+ my ($self, $offset, $base, $lookup, $fh) = @_;
+ my ($loc) = $fh->tell();
+ my ($res, $str);
+
+ return undef unless $offset;
+ $str = sprintf("%X", $base + $offset);
+ return $lookup->{' CACHE'}{$str} if defined $lookup->{' CACHE'}{$str};
+ $fh->seek($base + $offset, 0);
+ $res = Font::TTF::Anchor->new->read($fh);
+ $fh->seek($loc, 0);
+ $lookup->{' CACHE'}{$str} = $res;
+ return $res;
+}
+
+
+=head2 $t->fmt_value
+
+Returns the value format for a given value record
+
+=cut
+
+sub fmt_value
+{
+ my ($self, $value) = @_;
+ my ($fmt) = 0;
+ my ($n);
+
+ foreach $n (reverse qw(XPlacement YPlacement XAdvance YAdvance XPlaDevice YPlaDevice
+ XAdvDevice YAdvDevice XIdPlacement YIdPlacement XIdAdvance
+ YIdAdvance))
+ {
+ $fmt <<= 1;
+ $fmt |= 1 if (defined $value->{$n} && (ref $value->{$n} || $value->{$n}));
+ }
+ $fmt;
+}
+
+
+=head2 $t->out_value
+
+Returns the output string for the outputting of the value for a given format. Also
+updates the offset cache for any device tables referenced.
+
+=cut
+
+sub out_value
+{
+ my ($self, $value, $fmt, $tables, $offset) = @_;
+ my ($n, $flag, $out);
+
+ $flag = 1;
+ foreach $n (qw(XPlacement YPlacement XAdvance YAdvance))
+ {
+ $out .= pack('n', $value->{$n}) if ($flag & $fmt);
+ $flag <<= 1;
+ }
+ foreach $n (qw(XPlaDevice YPlaDevice XAdvDevice YAdvDevice))
+ {
+ if ($flag & $fmt)
+ {
+ $out .= pack('n', Font::TTF::Ttopen::ref_cache(
+ $value->{$n}, $tables, $offset + length($out)));
+ }
+ $flag <<= 1;
+ }
+ foreach $n (qw(XIdPlacement YIdPlacement XIdAdvance YIdAdvance))
+ {
+ $out .= pack('n', $value->{$n}) if ($flag & $fmt);
+ $flag <<= 1;
+ }
+ $out;
+}
+
+
+=head1 AUTHOR
+
+Martin Hosken Martin_Hosken at sil.org. See L<Font::TTF::Font> for copyright and
+licensing.
+
+=cut
+
+1;
+
Modified: packages/libfont-ttf-perl/trunk/lib/Font/TTF/GSUB.pm
===================================================================
--- packages/libfont-ttf-perl/trunk/lib/Font/TTF/GSUB.pm 2006-01-17 02:56:43 UTC (rev 1966)
+++ packages/libfont-ttf-perl/trunk/lib/Font/TTF/GSUB.pm 2006-01-17 03:07:20 UTC (rev 1967)
@@ -1,246 +1,246 @@
-package Font::TTF::GSUB;
-
-=head1 NAME
-
-Font::TTF::GSUB - Module support for the GSUB table in conjunction with TTOpen
-
-=head1 DESCRIPTION
-
-Handles the GSUB subtables in relation to Ttopen tables. Due to the variety of
-different lookup types, the data structures are not all that straightforward,
-although I have tried to make life easy for myself when using this!
-
-=head1 INSTANCE VARIABLES
-
-The structure of a GSUB table is the same as that given in L<Font::TTF::Ttopen>.
-Here we give some of the semantics specific to GSUB lookups.
-
-=over 4
-
-=item ACTION_TYPE
-
-This is a string taking one of 4 values indicating the nature of the information
-in the ACTION array of the rule:
-
-=over 8
-
-=item g
-
-The action contains a string of glyphs to replace the match string by
-
-=item l
-
-The action array contains a list of lookups and offsets to run, in order, on
-the matched string
-
-=item a
-
-The action array is an unordered set of optional replacements for the matched
-glyph. The application should make the selection somehow.
-
-=item o
-
-The action array is empty (in fact there is no rule array for this type of
-rule) and the ADJUST value should be added to the glyph id to find the replacement
-glyph id value
-
-=back
-
-=item MATCH_TYPE
-
-This indicates which type of information the various MATCH arrays (MATCH, PRE,
-POST) hold in the rule:
-
-=over 8
-
-=item g
-
-The array holds a string of glyph ids which should match exactly
-
-=item c
-
-The array holds a sequence of class definitions which each glyph should
-correspondingly match to
-
-=item o
-
-The array holds offsets to coverage tables
-
-=back
-
-=back
-
-=head1 CORRESPONDANCE TO LAYOUT TYPES
-
-The following table gives the values for ACTION_TYPE and MATCH_TYPE for each
-of the 11 different lookup types found in the GSUB table definition I have:
-
- 1.1 1.2 2 3 4 5.1 5.2 5.3 6.1 6.2 6.3
- ACTION_TYPE o g g a g l l l l l l
- MATCH_TYPE g g c o g c o
-
-Hopefully, the rest of the uses of the variables should make sense from this
-table.
-
-=head1 METHODS
-
-=cut
-
-use strict;
-use vars qw(@ISA);
-use Font::TTF::Utils;
-use Font::TTF::Ttopen;
-
- at ISA = qw(Font::TTF::Ttopen);
-
-=head2 $t->read_sub($fh, $lookup, $index)
-
-Asked by the superclass to read in from the given file the indexth subtable from
-lookup number lookup. The file is positioned ready for the read.
-
-=cut
-
-sub read_sub
-{
- my ($self, $fh, $main_lookup, $sindex) = @_;
- my ($type) = $main_lookup->{'TYPE'};
- my ($loc) = $fh->tell();
- my ($lookup) = $main_lookup->{'SUB'}[$sindex];
- my ($dat, $s, @subst, $t, $fmt, $cover, $count, $mcount, $scount, $i, $gid);
- my (@srec);
-
- if ($type == 6)
- {
- $fh->read($dat, 4);
- ($fmt, $cover) = TTF_Unpack('S2', $dat);
- if ($fmt < 3)
- {
- $fh->read($dat, 2);
- $count = TTF_Unpack('S', $dat);
- }
- } else
- {
- $fh->read($dat, 6);
- ($fmt, $cover, $count) = TTF_Unpack("S3", $dat);
- }
- unless ($fmt == 3 && ($type == 5 || $type == 6))
- { $lookup->{'COVERAGE'} = $self->read_cover($cover, $loc, $lookup, $fh, 1); }
-
- $lookup->{'FORMAT'} = $fmt;
- if ($type == 1 && $fmt == 1)
- {
- $lookup->{'ADJUST'} = $count;
- $lookup->{'ACTION_TYPE'} = 'o';
- } elsif ($type == 1 && $fmt == 2)
- {
- $fh->read($dat, $count << 1);
- @subst = TTF_Unpack('S*', $dat);
- foreach $s (@subst)
- { push(@{$lookup->{'RULES'}}, [{'ACTION' => [$s]}]); }
- $lookup->{'ACTION_TYPE'} = 'g';
- } elsif ($type == 2 || $type == 3)
- {
- $fh->read($dat, $count << 1); # number of offsets
- foreach $s (TTF_Unpack('S*', $dat))
- {
- $fh->seek($loc + $s, 0);
- $fh->read($dat, 2);
- $t = TTF_Unpack('S', $dat);
- $fh->read($dat, $t << 1);
- push(@{$lookup->{'RULES'}}, [{'ACTION' => [TTF_Unpack('S*', $dat)]}]);
- }
- $lookup->{'ACTION_TYPE'} = ($type == 2 ? 'g' : 'a');
- } elsif ($type == 4)
- {
- $fh->read($dat, $count << 1);
- foreach $s (TTF_Unpack('S*', $dat))
- {
- @subst = ();
- $fh->seek($loc + $s, 0);
- $fh->read($dat, 2);
- $t = TTF_Unpack('S', $dat);
- $fh->read($dat, $t << 1);
- foreach $t (TTF_Unpack('S*', $dat))
- {
- $fh->seek($loc + $s + $t, 0);
- $fh->read($dat, 4);
- ($gid, $mcount) = TTF_Unpack('S2', $dat);
- $fh->read($dat, ($mcount - 1) << 1);
- push(@subst, {'ACTION' => [$gid], 'MATCH' => [TTF_Unpack('S*', $dat)]});
- }
- push(@{$lookup->{'RULES'}}, [@subst]);
- }
- $lookup->{'ACTION_TYPE'} = 'g';
- $lookup->{'MATCH_TYPE'} = 'g';
- } elsif ($type == 5 || $type == 6)
- { $self->read_context($lookup, $fh, $type, $fmt, $cover, $count, $loc); }
- $lookup;
-}
-
-
-=head2 $t->extension
-
-Returns the table type number for the extension table
-
-=cut
-
-sub extension
-{ return 7; }
-
-
-=head2 $t->out_sub($fh, $lookup, $index)
-
-Passed the filehandle to output to, suitably positioned, the lookup and subtable
-index, this function outputs the subtable to $fh at that point.
-
-=cut
-
-sub out_sub
-{
- my ($self, $fh, $main_lookup, $index) = @_;
- my ($type) = $main_lookup->{'TYPE'};
- my ($lookup) = $main_lookup->{'SUB'}[$index];
- my ($fmt) = $lookup->{'FORMAT'};
- my ($out, $r, $t, $i, $j, $offc, $offd, $numd);
- my ($num) = $#{$lookup->{'RULES'}} + 1;
- my ($ctables) = {};
-
- if ($type == 1)
- {
- $out = pack("nn", $fmt, Font::TTF::Ttopen::ref_cache($lookup->{'COVERAGE'}, $ctables, 2));
- if ($fmt == 1)
- { $out .= pack("n", $lookup->{'ADJUST'}); }
- else
- {
- $out .= pack("n", $num);
- foreach $r (@{$lookup->{'RULES'}})
- { $out .= pack("n", $r->[0]{'ACTION'}[0]); }
- }
- } elsif ($type == 2 || $type == 3)
- {
- $out = pack("nnn", $fmt, Font::TTF::Ttopen::ref_cache($lookup->{'COVERAGE'}, $ctables, 2),
- $num);
- $out .= pack('n*', (0) x $num);
- $offc = length($out);
- for ($i = 0; $i < $num; $i++)
- {
- $out .= pack("n*", $#{$lookup->{'RULES'}[$i][0]{'ACTION'}} + 1,
- @{$lookup->{'RULES'}[$i][0]{'ACTION'}});
- substr($out, ($i << 1) + 6, 2) = pack('n', $offc);
- $offc = length($out);
- }
- } elsif ($type == 4 || $type == 5 || $type == 6)
- { $out = $self->out_context($lookup, $fh, $type, $fmt, $ctables, $out, $num); }
- Font::TTF::Ttopen::out_final($fh, $out, [[$ctables, 0]]);
- $lookup;
-}
-
-=head1 AUTHOR
-
-Martin Hosken Martin_Hosken at sil.org. See L<Font::TTF::Font> for copyright and
-licensing.
-
-=cut
-
-1;
-
+package Font::TTF::GSUB;
+
+=head1 NAME
+
+Font::TTF::GSUB - Module support for the GSUB table in conjunction with TTOpen
+
+=head1 DESCRIPTION
+
+Handles the GSUB subtables in relation to Ttopen tables. Due to the variety of
+different lookup types, the data structures are not all that straightforward,
+although I have tried to make life easy for myself when using this!
+
+=head1 INSTANCE VARIABLES
+
+The structure of a GSUB table is the same as that given in L<Font::TTF::Ttopen>.
+Here we give some of the semantics specific to GSUB lookups.
+
+=over 4
+
+=item ACTION_TYPE
+
+This is a string taking one of 4 values indicating the nature of the information
+in the ACTION array of the rule:
+
+=over 8
+
+=item g
+
+The action contains a string of glyphs to replace the match string by
+
+=item l
+
+The action array contains a list of lookups and offsets to run, in order, on
+the matched string
+
+=item a
+
+The action array is an unordered set of optional replacements for the matched
+glyph. The application should make the selection somehow.
+
+=item o
+
+The action array is empty (in fact there is no rule array for this type of
+rule) and the ADJUST value should be added to the glyph id to find the replacement
+glyph id value
+
+=back
+
+=item MATCH_TYPE
+
+This indicates which type of information the various MATCH arrays (MATCH, PRE,
+POST) hold in the rule:
+
+=over 8
+
+=item g
+
+The array holds a string of glyph ids which should match exactly
+
+=item c
+
+The array holds a sequence of class definitions which each glyph should
+correspondingly match to
+
+=item o
+
+The array holds offsets to coverage tables
+
+=back
+
+=back
+
+=head1 CORRESPONDANCE TO LAYOUT TYPES
+
+The following table gives the values for ACTION_TYPE and MATCH_TYPE for each
+of the 11 different lookup types found in the GSUB table definition I have:
+
+ 1.1 1.2 2 3 4 5.1 5.2 5.3 6.1 6.2 6.3
+ ACTION_TYPE o g g a g l l l l l l
+ MATCH_TYPE g g c o g c o
+
+Hopefully, the rest of the uses of the variables should make sense from this
+table.
+
+=head1 METHODS
+
+=cut
+
+use strict;
+use vars qw(@ISA);
+use Font::TTF::Utils;
+use Font::TTF::Ttopen;
+
+ at ISA = qw(Font::TTF::Ttopen);
+
+=head2 $t->read_sub($fh, $lookup, $index)
+
+Asked by the superclass to read in from the given file the indexth subtable from
+lookup number lookup. The file is positioned ready for the read.
+
+=cut
+
+sub read_sub
+{
+ my ($self, $fh, $main_lookup, $sindex) = @_;
+ my ($type) = $main_lookup->{'TYPE'};
+ my ($loc) = $fh->tell();
+ my ($lookup) = $main_lookup->{'SUB'}[$sindex];
+ my ($dat, $s, @subst, $t, $fmt, $cover, $count, $mcount, $scount, $i, $gid);
+ my (@srec);
+
+ if ($type == 6)
+ {
+ $fh->read($dat, 4);
+ ($fmt, $cover) = TTF_Unpack('S2', $dat);
+ if ($fmt < 3)
+ {
+ $fh->read($dat, 2);
+ $count = TTF_Unpack('S', $dat);
+ }
+ } else
+ {
+ $fh->read($dat, 6);
+ ($fmt, $cover, $count) = TTF_Unpack("S3", $dat);
+ }
+ unless ($fmt == 3 && ($type == 5 || $type == 6))
+ { $lookup->{'COVERAGE'} = $self->read_cover($cover, $loc, $lookup, $fh, 1); }
+
+ $lookup->{'FORMAT'} = $fmt;
+ if ($type == 1 && $fmt == 1)
+ {
+ $lookup->{'ADJUST'} = $count;
+ $lookup->{'ACTION_TYPE'} = 'o';
+ } elsif ($type == 1 && $fmt == 2)
+ {
+ $fh->read($dat, $count << 1);
+ @subst = TTF_Unpack('S*', $dat);
+ foreach $s (@subst)
+ { push(@{$lookup->{'RULES'}}, [{'ACTION' => [$s]}]); }
+ $lookup->{'ACTION_TYPE'} = 'g';
+ } elsif ($type == 2 || $type == 3)
+ {
+ $fh->read($dat, $count << 1); # number of offsets
+ foreach $s (TTF_Unpack('S*', $dat))
+ {
+ $fh->seek($loc + $s, 0);
+ $fh->read($dat, 2);
+ $t = TTF_Unpack('S', $dat);
+ $fh->read($dat, $t << 1);
+ push(@{$lookup->{'RULES'}}, [{'ACTION' => [TTF_Unpack('S*', $dat)]}]);
+ }
+ $lookup->{'ACTION_TYPE'} = ($type == 2 ? 'g' : 'a');
+ } elsif ($type == 4)
+ {
+ $fh->read($dat, $count << 1);
+ foreach $s (TTF_Unpack('S*', $dat))
+ {
+ @subst = ();
+ $fh->seek($loc + $s, 0);
+ $fh->read($dat, 2);
+ $t = TTF_Unpack('S', $dat);
+ $fh->read($dat, $t << 1);
+ foreach $t (TTF_Unpack('S*', $dat))
+ {
+ $fh->seek($loc + $s + $t, 0);
+ $fh->read($dat, 4);
+ ($gid, $mcount) = TTF_Unpack('S2', $dat);
+ $fh->read($dat, ($mcount - 1) << 1);
+ push(@subst, {'ACTION' => [$gid], 'MATCH' => [TTF_Unpack('S*', $dat)]});
+ }
+ push(@{$lookup->{'RULES'}}, [@subst]);
+ }
+ $lookup->{'ACTION_TYPE'} = 'g';
+ $lookup->{'MATCH_TYPE'} = 'g';
+ } elsif ($type == 5 || $type == 6)
+ { $self->read_context($lookup, $fh, $type, $fmt, $cover, $count, $loc); }
+ $lookup;
+}
+
+
+=head2 $t->extension
+
+Returns the table type number for the extension table
+
+=cut
+
+sub extension
+{ return 7; }
+
+
+=head2 $t->out_sub($fh, $lookup, $index)
+
+Passed the filehandle to output to, suitably positioned, the lookup and subtable
+index, this function outputs the subtable to $fh at that point.
+
+=cut
+
+sub out_sub
+{
+ my ($self, $fh, $main_lookup, $index) = @_;
+ my ($type) = $main_lookup->{'TYPE'};
+ my ($lookup) = $main_lookup->{'SUB'}[$index];
+ my ($fmt) = $lookup->{'FORMAT'};
+ my ($out, $r, $t, $i, $j, $offc, $offd, $numd);
+ my ($num) = $#{$lookup->{'RULES'}} + 1;
+ my ($ctables) = {};
+
+ if ($type == 1)
+ {
+ $out = pack("nn", $fmt, Font::TTF::Ttopen::ref_cache($lookup->{'COVERAGE'}, $ctables, 2));
+ if ($fmt == 1)
+ { $out .= pack("n", $lookup->{'ADJUST'}); }
+ else
+ {
+ $out .= pack("n", $num);
+ foreach $r (@{$lookup->{'RULES'}})
+ { $out .= pack("n", $r->[0]{'ACTION'}[0]); }
+ }
+ } elsif ($type == 2 || $type == 3)
+ {
+ $out = pack("nnn", $fmt, Font::TTF::Ttopen::ref_cache($lookup->{'COVERAGE'}, $ctables, 2),
+ $num);
+ $out .= pack('n*', (0) x $num);
+ $offc = length($out);
+ for ($i = 0; $i < $num; $i++)
+ {
+ $out .= pack("n*", $#{$lookup->{'RULES'}[$i][0]{'ACTION'}} + 1,
+ @{$lookup->{'RULES'}[$i][0]{'ACTION'}});
+ substr($out, ($i << 1) + 6, 2) = pack('n', $offc);
+ $offc = length($out);
+ }
+ } elsif ($type == 4 || $type == 5 || $type == 6)
+ { $out = $self->out_context($lookup, $fh, $type, $fmt, $ctables, $out, $num); }
+ Font::TTF::Ttopen::out_final($fh, $out, [[$ctables, 0]]);
+ $lookup;
+}
+
+=head1 AUTHOR
+
+Martin Hosken Martin_Hosken at sil.org. See L<Font::TTF::Font> for copyright and
+licensing.
+
+=cut
+
+1;
+
Modified: packages/libfont-ttf-perl/trunk/lib/Font/TTF/Glyf.pm
===================================================================
--- packages/libfont-ttf-perl/trunk/lib/Font/TTF/Glyf.pm 2006-01-17 02:56:43 UTC (rev 1966)
+++ packages/libfont-ttf-perl/trunk/lib/Font/TTF/Glyf.pm 2006-01-17 03:07:20 UTC (rev 1967)
@@ -1,158 +1,158 @@
-package Font::TTF::Glyf;
-
-=head1 NAME
-
-Font::TTF::Glyf - The Glyf data table
-
-=head1 DESCRIPTION
-
-This is a stub table. The real data is held in the loca table. If you want to get a glyf
-look it up in the loca table as C<$f->{'loca'}{'glyphs'}[$num]>. It won't be here!
-
-The difference between reading this table as opposed to the loca table is that
-reading this table will cause updated glyphs to be written out rather than just
-copying the glyph information from the input file. This causes font writing to be
-slower. So read the glyf as opposed to the loca table if you want to change glyf
-data. Read the loca table only if you are just wanting to read the glyf information.
-
-This class is used when writing the glyphs though.
-
-=head1 METHODS
-
-=cut
-
-
-use strict;
-use vars qw(@ISA);
- at ISA = qw(Font::TTF::Table);
-
-=head2 $t->read
-
-Reads the C<loca> table instead!
-
-=cut
-
-sub read
-{
- my ($self) = @_;
-
- $self->{' PARENT'}{'loca'}->read;
- $self->{' read'} = 1;
- $self;
-}
-
-
-=head2 $t->out($fh)
-
-Writes out all the glyphs in the parent's location table, calculating a new
-output location for each one.
-
-=cut
-
-sub out
-{
- my ($self, $fh) = @_;
- my ($i, $loca, $offset, $numGlyphs);
-
- return $self->SUPER::out($fh) unless $self->{' read'};
-
- $loca = $self->{' PARENT'}{'loca'}{'glyphs'};
- $numGlyphs = $self->{' PARENT'}{'maxp'}{'numGlyphs'};
-
- $offset = 0;
- for ($i = 0; $i < $numGlyphs; $i++)
- {
- next unless defined $loca->[$i];
- $loca->[$i]->update;
- $loca->[$i]{' OUTLOC'} = $offset;
- $loca->[$i]->out($fh);
- $offset += $loca->[$i]{' OUTLEN'};
- }
- $self->{' PARENT'}{'head'}{'indexToLocFormat'} = ($offset >= 0x20000);
- $self;
-}
-
-
-=head2 $t->out_xml($context, $depth)
-
-Outputs all the glyphs in the glyph table just where they are supposed to be output!
-
-=cut
-
-sub out_xml
-{
- my ($self, $context, $depth) = @_;
- my ($fh) = $context->{'fh'};
- my ($loca, $i, $numGlyphs);
-
- $loca = $self->{' PARENT'}{'loca'}{'glyphs'};
- $numGlyphs = $self->{' PARENT'}{'maxp'}{'numGlyphs'};
-
- for ($i = 0; $i < $numGlyphs; $i++)
- {
- $context->{'gid'} = $i;
- $loca->[$i]->out_xml($context, $depth) if (defined $loca->[$i]);
- }
-
- $self;
-}
-
-
-=head2 $t->XML_start($context, $tag, %attrs)
-
-Pass control to glyphs as they occur
-
-=cut
-
-sub XML_start
-{
- my ($self) = shift;
- my ($context, $tag, %attrs) = @_;
-
- if ($tag eq 'glyph')
- {
- $context->{'tree'}[-1] = Font::TTF::Glyph->new(read => 2, PARENT => $self->{' PARENT'});
- $context->{'receiver'} = $context->{'tree'}[-1];
- }
-}
-
-
-=head2 $t->XML_end($context, $tag, %attrs)
-
-Collect up glyphs and put them into the loca table
-
-=cut
-
-sub XML_end
-{
- my ($self) = shift;
- my ($context, $tag, %attrs) = @_;
-
- if ($tag eq 'glyph')
- {
- unless (defined $context->{'glyphs'})
- {
- if (defined $self->{' PARENT'}{'loca'})
- { $context->{'glyphs'} = $self->{' PARENT'}{'loca'}{'glyphs'}; }
- else
- { $context->{'glyphs'} = []; }
- }
- $context->{'glyphs'}[$attrs{'gid'}] = $context->{'tree'}[-1];
- return $context;
- } else
- { return $self->SUPER::XML_end(@_); }
-}
-
-1;
-
-=head1 BUGS
-
-None known
-
-=head1 AUTHOR
-
-Martin Hosken Martin_Hosken at sil.org. See L<Font::TTF::Font> for copyright and
-licensing.
-
-=cut
-
+package Font::TTF::Glyf;
+
+=head1 NAME
+
+Font::TTF::Glyf - The Glyf data table
+
+=head1 DESCRIPTION
+
+This is a stub table. The real data is held in the loca table. If you want to get a glyf
+look it up in the loca table as C<$f->{'loca'}{'glyphs'}[$num]>. It won't be here!
+
+The difference between reading this table as opposed to the loca table is that
+reading this table will cause updated glyphs to be written out rather than just
+copying the glyph information from the input file. This causes font writing to be
+slower. So read the glyf as opposed to the loca table if you want to change glyf
+data. Read the loca table only if you are just wanting to read the glyf information.
+
+This class is used when writing the glyphs though.
+
+=head1 METHODS
+
+=cut
+
+
+use strict;
+use vars qw(@ISA);
+ at ISA = qw(Font::TTF::Table);
+
+=head2 $t->read
+
+Reads the C<loca> table instead!
+
+=cut
+
+sub read
+{
+ my ($self) = @_;
+
+ $self->{' PARENT'}{'loca'}->read;
+ $self->{' read'} = 1;
+ $self;
+}
+
+
+=head2 $t->out($fh)
+
+Writes out all the glyphs in the parent's location table, calculating a new
+output location for each one.
+
+=cut
+
+sub out
+{
+ my ($self, $fh) = @_;
+ my ($i, $loca, $offset, $numGlyphs);
+
+ return $self->SUPER::out($fh) unless $self->{' read'};
+
+ $loca = $self->{' PARENT'}{'loca'}{'glyphs'};
+ $numGlyphs = $self->{' PARENT'}{'maxp'}{'numGlyphs'};
+
+ $offset = 0;
+ for ($i = 0; $i < $numGlyphs; $i++)
+ {
+ next unless defined $loca->[$i];
+ $loca->[$i]->update;
+ $loca->[$i]{' OUTLOC'} = $offset;
+ $loca->[$i]->out($fh);
+ $offset += $loca->[$i]{' OUTLEN'};
+ }
+ $self->{' PARENT'}{'head'}{'indexToLocFormat'} = ($offset >= 0x20000);
+ $self;
+}
+
+
+=head2 $t->out_xml($context, $depth)
+
+Outputs all the glyphs in the glyph table just where they are supposed to be output!
+
+=cut
+
+sub out_xml
+{
+ my ($self, $context, $depth) = @_;
+ my ($fh) = $context->{'fh'};
+ my ($loca, $i, $numGlyphs);
+
+ $loca = $self->{' PARENT'}{'loca'}{'glyphs'};
+ $numGlyphs = $self->{' PARENT'}{'maxp'}{'numGlyphs'};
+
+ for ($i = 0; $i < $numGlyphs; $i++)
+ {
+ $context->{'gid'} = $i;
+ $loca->[$i]->out_xml($context, $depth) if (defined $loca->[$i]);
+ }
+
+ $self;
+}
+
+
+=head2 $t->XML_start($context, $tag, %attrs)
+
+Pass control to glyphs as they occur
+
+=cut
+
+sub XML_start
+{
+ my ($self) = shift;
+ my ($context, $tag, %attrs) = @_;
+
+ if ($tag eq 'glyph')
+ {
+ $context->{'tree'}[-1] = Font::TTF::Glyph->new(read => 2, PARENT => $self->{' PARENT'});
+ $context->{'receiver'} = $context->{'tree'}[-1];
+ }
+}
+
+
+=head2 $t->XML_end($context, $tag, %attrs)
+
+Collect up glyphs and put them into the loca table
+
+=cut
+
+sub XML_end
+{
+ my ($self) = shift;
+ my ($context, $tag, %attrs) = @_;
+
+ if ($tag eq 'glyph')
+ {
+ unless (defined $context->{'glyphs'})
+ {
+ if (defined $self->{' PARENT'}{'loca'})
+ { $context->{'glyphs'} = $self->{' PARENT'}{'loca'}{'glyphs'}; }
+ else
+ { $context->{'glyphs'} = []; }
+ }
+ $context->{'glyphs'}[$attrs{'gid'}] = $context->{'tree'}[-1];
+ return $context;
+ } else
+ { return $self->SUPER::XML_end(@_); }
+}
+
+1;
+
+=head1 BUGS
+
+None known
+
+=head1 AUTHOR
+
+Martin Hosken Martin_Hosken at sil.org. See L<Font::TTF::Font> for copyright and
+licensing.
+
+=cut
+
Modified: packages/libfont-ttf-perl/trunk/lib/Font/TTF/Glyph.pm
===================================================================
--- packages/libfont-ttf-perl/trunk/lib/Font/TTF/Glyph.pm 2006-01-17 02:56:43 UTC (rev 1966)
+++ packages/libfont-ttf-perl/trunk/lib/Font/TTF/Glyph.pm 2006-01-17 03:07:20 UTC (rev 1967)
@@ -1,815 +1,815 @@
-package Font::TTF::Glyph;
-
-=head1 NAME
-
-Font::TTF::Glyph - Holds a single glyph's information
-
-=head1 DESCRIPTION
-
-This is a single glyph description as held in a TT font. On creation only its
-header is read. Thus you can get the bounding box of each glyph without having
-to read all the other information.
-
-=head1 INSTANCE VARIABLES
-
-In addition to the named variables in a glyph header (C<xMin> etc.), there are
-also all capital instance variables for holding working information, mostly
-from the location table.
-
-The standard attributes each glyph has are:
-
- numberOfContours
- xMin
- yMin
- xMax
- yMax
-
-There are also other, derived, instance variables for each glyph which are read
-when the whole glyph is read (via C<read_dat>):
-
-=over 4
-
-=item instLen
-
-Number of bytes in the hinting instructions (Warning this variable is deprecated,
-use C<length($g->{'hints'})> instead).
-
-=item hints
-
-The string containing the hinting code for the glyph
-
-=back
-
-In addition there are other attribute like instance variables for simple glyphs:
-
-=over 4
-
-For each contour there is:
-
-=over 4
-
-=item endPoints
-
-An array of endpoints for each contour in the glyph. There are
-C<numberOfContours> contours in a glyph. The number of points in a glyph is
-equal to the highest endpoint of a contour.
-
-=back
-
-There are also a number of arrays indexed by point number
-
-=over 4
-
-=item flags
-
-The flags associated with reading this point. The flags for a point are
-recalculated for a point when it is C<update>d. Thus the flags are not very
-useful. The only important bit is bit 0 which indicates whether the point is
-an 'on' curve point, or an 'off' curve point.
-
-=item x
-
-The absolute x co-ordinate of the point.
-
-=item y
-
-The absolute y co-ordinate of the point
-
-=back
-
-=back
-
-For composite glyphs there are other variables
-
-=over 4
-
-=item metric
-
-This holds the component number (not its glyph number) of the component from
-which the metrics for this glyph should be taken.
-
-=item comps
-
-This is an array of hashes for each component. Each hash has a number of
-elements:
-
-=over 4
-
-=item glyph
-
-The glyph number of the glyph which comprises this component of the composite.
-
-=item args
-
-An array of two arguments which may be an x, y co-ordinate or two attachment
-points (one on the base glyph the other on the component). See flags for details.
-
-=item flag
-
-The flag for this component
-
-=item scale
-
-A 4 number array for component scaling. This allows stretching, rotating, etc.
-Note that scaling applies to placement co-ordinates (rather than attachment points)
-before locating rather than after.
-
-=back
-
-=item numPoints
-
-This is a generated value which contains the number of components read in for this
-compound glyph.
-
-=back
-
-The private instance variables are:
-
-=over 4
-
-=item INFILE (P)
-
-The input file form which to read any information
-
-=item LOC (P)
-
-Location relative to the start of the glyf table in the read file
-
-=item BASE (P)
-
-The location of the glyf table in the read file
-
-=item LEN (P)
-
-This is the number of bytes required by the glyph. It should be kept up to date
-by calling the C<update> method whenever any of the glyph content changes.
-
-=item OUTLOC (P)
-
-Location relative to the start of the glyf table. This variable is only active
-whilst the output process is going on. It is used to inform the location table
-where the glyph's location is, since the glyf table is output before the loca
-table due to alphabetical ordering.
-
-=item OUTLEN (P)
-
-This indicates the length of the glyph data when it is output. This more
-accurately reflects the internal memory form than the C<LEN> variable which
-only reflects the read file length. The C<OUTLEN> variable is only set after
-calling C<out> or C<out_dat>.
-
-=back
-
-=head2 Editing
-
-If you want to edit a glyph in some way, then you should read_dat the glyph, then
-make your changes and then update the glyph or set the $g->{' isdirty'} variable.
-It is the application's duty to ensure that the following instance variables are
-correct, from which update will calculate the rest, including the bounding box
-information.
-
- numPoints
- numberOfContours
- endPoints
- x, y, flags (only flags bit 0)
- instLen
- hints
-
-For components, the numPoints, x, y, endPoints & flags are not required but
-the following information is required for each component.
-
- flag (bits 2, 10, 11, 12)
- glyph
- args
- scale
- metric (glyph instance variable)
-
-
-=head1 METHODS
-
-=cut
-
-use strict;
-use vars qw(%fields @field_info);
-use Font::TTF::Utils;
-use Font::TTF::Table;
-
- at field_info = (
- 'numberOfContours' => 's',
- 'xMin' => 's',
- 'yMin' => 's',
- 'xMax' => 's',
- 'yMax' => 's');
-
-sub init
-{
- my ($k, $v, $c, $i);
- for ($i = 0; $i < $#field_info; $i += 2)
- {
- ($k, $v, $c) = TTF_Init_Fields($field_info[$i], $c, $field_info[$i + 1]);
- next unless defined $k && $k ne "";
- $fields{$k} = $v;
- }
-}
-
-
-=head1 Font::TTF::Glyph->new(%parms)
-
-Creates a new glyph setting various instance variables
-
-=cut
-
-sub new
-{
- my ($class, %parms) = @_;
- my ($self) = {};
- my ($p);
-
- bless $self, $class;
- foreach $p (keys %parms)
- { $self->{" $p"} = $parms{$p}; }
- init unless defined $fields{'xMin'};
- $self;
-}
-
-
-=head2 $g->read
-
-Reads the header component of the glyph (bounding box, etc.) and also the
-glyph content, but into a data field rather than breaking it down into
-its constituent structures. Use read_dat for this.
-
-=cut
-
-sub read
-{
- my ($self) = @_;
- my ($fh) = $self->{' INFILE'};
- my ($dat);
-
- return $self if $self->{' read'};
- $self->{' read'} = 1;
- $fh->seek($self->{' LOC'} + $self->{' BASE'}, 0);
- $fh->read($self->{' DAT'}, $self->{' LEN'});
- TTF_Read_Fields($self, $self->{' DAT'}, \%fields);
- $self;
-}
-
-
-=head2 $g->read_dat
-
-Reads the contents of the glyph (components and curves, etc.) from the memory
-store C<DAT> into structures within the object. Then, to indicate where the
-master form of the data is, it deletes the C<DAT> instance variable.
-
-=cut
-
-sub read_dat
-{
- my ($self) = @_;
- my ($dat, $num, $max, $i, $flag, $len, $val, $val1, $fp);
-
- return $self if $self->{' read'} > 1;
- $self->read unless $self->{' read'};
- $dat = $self->{' DAT'};
- $fp = 10;
- $num = $self->{'numberOfContours'};
- if ($num > 0)
- {
- $self->{'endPoints'} = [unpack("n*", substr($dat, $fp, $num << 1))];
- $fp += $num << 1;
- $max = 0;
- foreach (@{$self->{'endPoints'}})
- { $max = $_ if $_ > $max; }
- $max++;
- $self->{'numPoints'} = $max;
- $self->{'instLen'} = unpack("n", substr($dat, $fp));
- $self->{'hints'} = substr($dat, $fp + 2, $self->{'instLen'});
- $fp += 2 + $self->{'instLen'};
-# read the flags array
- for ($i = 0; $i < $max; $i++)
- {
- $flag = unpack("C", substr($dat, $fp++));
- $self->{'flags'}[$i] = $flag;
- if ($flag & 8)
- {
- $len = unpack("C", substr($dat, $fp++));
- while ($len-- > 0)
- {
- $i++;
- $self->{'flags'}[$i] = $flag;
- }
- }
- }
-#read the x array
- for ($i = 0; $i < $max; $i++)
- {
- $flag = $self->{'flags'}[$i];
- if ($flag & 2)
- {
- $val = unpack("C", substr($dat, $fp++));
- $val = -$val unless ($flag & 16);
- } elsif ($flag & 16)
- { $val = 0; }
- else
- {
- $val = TTF_Unpack("s", substr($dat, $fp));
- $fp += 2;
- }
- $self->{'x'}[$i] = $i == 0 ? $val : $self->{'x'}[$i - 1] + $val;
- }
-#read the y array
- for ($i = 0; $i < $max; $i++)
- {
- $flag = $self->{'flags'}[$i];
- if ($flag & 4)
- {
- $val = unpack("C", substr($dat, $fp++));
- $val = -$val unless ($flag & 32);
- } elsif ($flag & 32)
- { $val = 0; }
- else
- {
- $val = TTF_Unpack("s", substr($dat, $fp));
- $fp += 2;
- }
- $self->{'y'}[$i] = $i == 0 ? $val : $self->{'y'}[$i - 1] + $val;
- }
- }
-
-# compound glyph
- elsif ($num < 0)
- {
- $flag = 1 << 5; # cheat to get the loop going
- for ($i = 0; $flag & 32; $i++)
- {
- ($flag, $self->{'comps'}[$i]{'glyph'}) = unpack("n2", substr($dat, $fp));
- $fp += 4;
- $self->{'comps'}[$i]{'flag'} = $flag;
- if ($flag & 1) # ARGS1_AND_2_ARE_WORDS
- {
- $self->{'comps'}[$i]{'args'} = [TTF_Unpack("s2", substr($dat, $fp))];
- $fp += 4;
- } else
- {
- $self->{'comps'}[$i]{'args'} = [unpack("c2", substr($dat, $fp))];
- $fp += 2;
- }
-
- if ($flag & 8)
- {
- $val = TTF_Unpack("F", substr($dat, $fp));
- $fp += 2;
- $self->{'comps'}[$i]{'scale'} = [$val, 0, 0, $val];
- } elsif ($flag & 64)
- {
- ($val, $val1) = TTF_Unpack("F2", substr($dat, $fp));
- $fp += 4;
- $self->{'comps'}[$i]{'scale'} = [$val, 0, 0, $val1];
- } elsif ($flag & 128)
- {
- $self->{'comps'}[$i]{'scale'} = [TTF_Unpack("F4", substr($dat, $fp))];
- $fp += 8;
- }
- $self->{'metric'} = $i if ($flag & 512);
- }
- $self->{'numPoints'} = $i;
- if ($flag & 256) # HAVE_INSTRUCTIONS
- {
- $self->{'instLen'} = unpack("n", substr($dat, $fp));
- $self->{'hints'} = substr($dat, $fp + 2, $self->{'instLen'});
- $fp += 2 + $self->{'instLen'};
- }
- }
- return undef if ($fp > length($dat));
- $self->{' read'} = 2;
- $self;
-}
-
-
-=head2 $g->out($fh)
-
-Writes the glyph data to outfile
-
-=cut
-
-sub out
-{
- my ($self, $fh) = @_;
-
- $self->read unless $self->{' read'};
- $self->update if $self->{' isDirty'};
- $fh->print($self->{' DAT'});
- $self->{' OUTLEN'} = length($self->{' DAT'});
- $self;
-}
-
-
-=head2 $g->out_xml($context, $depth)
-
-Outputs an XML description of the glyph
-
-=cut
-
-sub out_xml
-{
- my ($self, $context, $depth) = @_;
- my ($addr) = ($self =~ m/\((.+)\)$/o);
- my ($k, $ndepth);
-
- if ($context->{'addresses'}{$addr})
- {
- $context->{'fh'}->printf("%s<glyph gid='%s' id_ref='%s'/>\n", $depth, $context->{'gid'}, $addr);
- return $self;
- }
- else
- {
- $context->{'fh'}->printf("%s<glyph gid='%s' id='%s'>\n", $depth, $context->{'gid'}, $addr);
- }
-
- $ndepth = $depth . $context->{'indent'};
- $self->read_dat;
- foreach $k (sort grep {$_ !~ m/^\s/o} keys %{$self})
- {
- $self->XML_element($context, $ndepth, $k, $self->{$k});
- }
- $context->{'fh'}->print("$depth</glyph>\n");
- delete $context->{'done_points'};
- $self;
-}
-
-
-sub XML_element
-{
- my ($self, $context, $depth, $key, $val) = @_;
- my ($fh) = $context->{'fh'};
- my ($dind) = $depth . $context->{'indent'};
- my ($i);
-
- if ($self->{'numberOfContours'} >= 0 && ($key eq 'x' || $key eq 'y' || $key eq 'flags'))
- {
- return $self if ($context->{'done_points'});
- $context->{'done_points'} = 1;
-
- $fh->print("$depth<points>\n");
- for ($i = 0; $i <= $#{$self->{'flags'}}; $i++)
- { $fh->printf("%s<point x='%s' y='%s' flags='0x%02X'/>\n", $dind,
- $self->{'x'}[$i], $self->{'y'}[$i], $self->{'flags'}[$i]); }
- $fh->print("$depth</points>\n");
- }
- elsif ($key eq 'hints')
- {
- my ($dat);
- $fh->print("$depth<hints>\n");
-# Font::TTF::Utils::XML_hexdump($context, $depth . $context->{'indent'}, $self->{'hints'});
- $dat = Font::TTF::Utils::XML_binhint($self->{'hints'});
- $dat =~ s/\n(?!$)/\n$depth$context->{'indent'}/mg;
- $fh->print("$depth$context->{'indent'}$dat");
- $fh->print("$depth</hints>\n");
- }
- else
- { return Font::TTF::Table::XML_element(@_); }
-
- $self;
-}
-
-
-=head2 $g->update
-
-Generates a C<$self->{'DAT'}> from the internal structures, if the data has
-been read into structures in the first place. If you are building a glyph
-from scratch you will need to set the instance variable C<' read'> to 2 (or
-something > 1) for the update to work.
-
-=cut
-
-sub update
-{
- my ($self) = @_;
- my ($dat, $loc, $len, $flag, $x, $y, $i, $comp, $num);
-
- return $self unless (defined $self->{' read'} && $self->{' read'} > 1);
- $self->update_bbox;
- $self->{' DAT'} = TTF_Out_Fields($self, \%fields, 10);
- $num = $self->{'numberOfContours'};
- if ($num > 0)
- {
- $self->{' DAT'} .= pack("n*", @{$self->{'endPoints'}});
- $len = $self->{'instLen'};
- $self->{' DAT'} .= pack("n", $len);
- $self->{' DAT'} .= pack("a" . $len, substr($self->{'hints'}, 0, $len)) if ($len > 0);
- for ($i = 0; $i < $self->{'numPoints'}; $i++)
- {
- $flag = $self->{'flags'}[$i] & 1;
- if ($i == 0)
- {
- $x = $self->{'x'}[$i];
- $y = $self->{'y'}[$i];
- } else
- {
- $x = $self->{'x'}[$i] - $self->{'x'}[$i - 1];
- $y = $self->{'y'}[$i] - $self->{'y'}[$i - 1];
- }
- $flag |= 16 if ($x == 0);
- $flag |= 32 if ($y == 0);
- if (($flag & 16) == 0 && $x < 256 && $x > -256)
- {
- $flag |= 2;
- $flag |= 16 if ($x >= 0);
- }
- if (($flag & 32) == 0 && $y < 256 && $y > -256)
- {
- $flag |= 4;
- $flag |= 32 if ($y >= 0);
- }
- $self->{' DAT'} .= pack("C", $flag); # sorry no repeats
- $self->{'flags'}[$i] = $flag;
- }
- for ($i = 0; $i < $self->{'numPoints'}; $i++)
- {
- $flag = $self->{'flags'}[$i];
- $x = $self->{'x'}[$i] - (($i == 0) ? 0 : $self->{'x'}[$i - 1]);
- if (($flag & 18) == 0)
- { $self->{' DAT'} .= TTF_Pack("s", $x); }
- elsif (($flag & 18) == 18)
- { $self->{' DAT'} .= pack("C", $x); }
- elsif (($flag & 18) == 2)
- { $self->{' DAT'} .= pack("C", -$x); }
- }
- for ($i = 0; $i < $self->{'numPoints'}; $i++)
- {
- $flag = $self->{'flags'}[$i];
- $y = $self->{'y'}[$i] - (($i == 0) ? 0 : $self->{'y'}[$i - 1]);
- if (($flag & 36) == 0)
- { $self->{' DAT'} .= TTF_Pack("s", $y); }
- elsif (($flag & 36) == 36)
- { $self->{' DAT'} .= pack("C", $y); }
- elsif (($flag & 36) == 4)
- { $self->{' DAT'} .= pack("C", -$y); }
- }
- }
-
- elsif ($num < 0)
- {
- for ($i = 0; $i <= $#{$self->{'comps'}}; $i++)
- {
- $comp = $self->{'comps'}[$i];
- $flag = $comp->{'flag'} & 7158; # bits 2,10,11,12
- $flag |= 1 unless ($comp->{'args'}[0] > -129 && $comp->{'args'}[0] < 128
- && $comp->{'args'}[1] > -129 && $comp->{'args'}[1] < 128);
- if (defined $comp->{'scale'})
- {
- if ($comp->{'scale'}[1] == 0 && $comp->{'scale'}[2] == 0)
- {
- if ($comp->{'scale'}[0] == $comp->{'scale'}[3])
- { $flag |= 8 unless ($comp->{'scale'}[0] == 0
- || abs(abs($comp->{'scale'}[0]) - 1.) < .001); }
- else
- { $flag |= 64; }
- } else
- { $flag |= 128; }
- }
-
- $flag |= 512 if (defined $self->{'metric'} && $self->{'metric'} == $i);
- if ($i == $#{$self->{'comps'}})
- { $flag |= 256 if (defined $self->{'instLen'} && $self->{'instLen'} > 0); }
- else
- { $flag |= 32; }
-
- $self->{' DAT'} .= pack("n", $flag);
- $self->{' DAT'} .= pack("n", $comp->{'glyph'});
- $comp->{'flag'} = $flag;
-
- if ($flag & 1)
- { $self->{' DAT'} .= TTF_Pack("s2", @{$comp->{'args'}}); }
- else
- { $self->{' DAT'} .= pack("CC", @{$comp->{'args'}}); }
-
- if ($flag & 8)
- { $self->{' DAT'} .= TTF_Pack("F", $comp->{'scale'}[0]); }
- elsif ($flag & 64)
- { $self->{' DAT'} .= TTF_Pack("F2", $comp->{'scale'}[0], $comp->{'scale'}[3]); }
- elsif ($flag & 128)
- { $self->{' DAT'} .= TTF_Pack("F4", @{$comp->{'scale'}}); }
- }
- if (defined $self->{'instLen'} && $self->{'instLen'} > 0)
- {
- $len = $self->{'instLen'};
- $self->{' DAT'} .= pack("n", $len);
- $self->{' DAT'} .= pack("a" . $len, substr($self->{'hints'}, 0, $len));
- }
- }
- $self->{' DAT'} .= "\000" if (length($self->{' DAT'}) & 1);
- $self->{' OUTLEN'} = length($self->{' DAT'});
- $self->{' read'} = 2; # changed from 1 to 2 so we don't read_dat() again
-# we leave numPoints and instLen since maxp stats use this
- $self;
-}
-
-
-=head2 $g->update_bbox
-
-Updates the bounding box for this glyph according to the points in the glyph
-
-=cut
-
-sub update_bbox
-{
- my ($self) = @_;
- my ($num, $maxx, $minx, $maxy, $miny, $i, $comp, $x, $y, $compg);
-
- return $self unless $self->{' read'} > 1; # only if read_dat done
- $miny = $minx = 65537; $maxx = $maxy = -65537;
- $num = $self->{'numberOfContours'};
- if ($num > 0)
- {
- for ($i = 0; $i < $self->{'numPoints'}; $i++)
- {
- ($x, $y) = ($self->{'x'}[$i], $self->{'y'}[$i]);
-
- $maxx = $x if ($x > $maxx);
- $minx = $x if ($x < $minx);
- $maxy = $y if ($y > $maxy);
- $miny = $y if ($y < $miny);
- }
- }
-
- elsif ($num < 0)
- {
- foreach $comp (@{$self->{'comps'}})
- {
- my ($gnx, $gny, $gxx, $gxy);
- my ($sxx, $sxy, $syx, $syy);
-
- $compg = $self->{' PARENT'}{'loca'}{'glyphs'}[$comp->{'glyph'}]->read->update_bbox;
- ($gnx, $gny, $gxx, $gxy) = @{$compg}{'xMin', 'yMin', 'xMax', 'yMax'};
- if (defined $comp->{'scale'})
- {
- ($sxx, $sxy, $syx, $syy) = @{$comp->{'scale'}};
- ($gnx, $gny, $gxx, $gxy) = ($gnx*$sxx+$gny*$syx + $comp->{'args'}[0],
- $gnx*$sxy+$gny*$syy + $comp->{'args'}[1],
- $gxx*$sxx+$gxy*$syx + $comp->{'args'}[0],
- $gxx*$sxy+$gxy*$syy + $comp->{'args'}[1]);
- } elsif ($comp->{'args'}[0] || $comp->{'args'}[1])
- {
- $gnx += $comp->{'args'}[0];
- $gny += $comp->{'args'}[1];
- $gxx += $comp->{'args'}[0];
- $gxy += $comp->{'args'}[1];
- }
- $maxx = $gxx if $gxx > $maxx;
- $minx = $gnx if $gnx < $minx;
- $maxy = $gxy if $gxy > $maxy;
- $miny = $gny if $gny < $miny;
- }
- }
- $self->{'xMax'} = $maxx;
- $self->{'xMin'} = $minx;
- $self->{'yMax'} = $maxy;
- $self->{'yMin'} = $miny;
- $self;
-}
-
-
-=head2 $g->maxInfo
-
-Returns lots of information about a glyph so that the C<maxp> table can update
-itself.
-
-=cut
-
-sub maxInfo
-{
- my ($self) = @_;
- my (@res, $i, @n);
-
- $self->read_dat; # make sure we've read some data
- $res[4] = length($self->{'hints'}) if defined $self->{'hints'};
- if ($self->{'numberOfContours'} > 0)
- {
- $res[2] = $res[0] = $self->{'numPoints'};
- $res[3] = $res[1] = $self->{'numberOfContours'};
- $res[6] = 1;
- } elsif ($self->{'numberOfContours'} < 0)
- {
- $res[6] = 1;
- for ($i = 0; $i <= $#{$self->{'comps'}}; $i++)
- {
- @n = $self->{' PARENT'}{'loca'}{'glyphs'}[$self->{'comps'}[$i]{'glyph'}]->maxInfo;
- $res[2] += $n[2] == 0 ? $n[0] : $n[2];
- $res[3] += $n[3] == 0 ? $n[1] : $n[3];
- $res[5]++;
- $res[6] = $n[6] + 1 if ($n[6] >= $res[6]);
- }
- }
- @res;
-}
-
-=head2 $g->empty
-
-Empties the glyph of all information to the level of not having been read.
-Useful for saving memory in apps with many glyphs being read
-
-=cut
-
-sub empty
-{
- my ($self) = @_;
- my (%keep) = map {(" $_" => 1)} ('LOC', 'OUTLOC', 'PARENT', 'INFILE', 'BASE',
- 'OUTLEN', 'LEN');
- map {delete $self->{$_} unless $keep{$_}} keys %$self;
-
- $self;
-}
-
-
-=head2 $g->get_points
-
-This method creates point information for a compound glyph. The information is
-stored in the same place as if the glyph was not a compound, but since
-numberOfContours is negative, the glyph is still marked as being a compound
-
-=cut
-
-sub get_points
-{
- my ($self) = @_;
- my ($comp, $compg, $nump, $e, $i);
-
- $self->read_dat;
- return undef unless ($self->{'numberOfContours'} < 0);
-
- foreach $comp (@{$self->{'comps'}})
- {
- $compg = $self->{' PARENT'}{'loca'}{'glyphs'}[$comp->{'glyph'}]->read;
- $compg->get_points;
-
- for ($i = 0; $i < $compg->{'numPoints'}; $i++)
- {
- my ($x, $y) = ($compg->{'x'}[$i], $compg->{'y'}[$i]);
- if (defined $comp->{'scale'})
- {
- ($x, $y) = ($x * $comp->{'scale'}[0] + $y * $comp->{'scale'}[2],
- $x * $comp->{'scale'}[1] + $y * $comp->{'scale'}[3]);
- }
- if (defined $comp->{'args'})
- { ($x, $y) = ($x + $comp->{'args'}[0], $y + $comp->{'args'}[1]); }
- push (@{$self->{'x'}}, $x);
- push (@{$self->{'y'}}, $y);
- }
- foreach $e (@{$compg->{'endPoints'}})
- { push (@{$self->{'endPoints'}}, $e + $nump); }
- $nump += $compg->{'numPoints'};
- }
- $self->{'numPoints'} = $nump;
- $self;
-}
-
-
-=head2 $g->get_refs
-
-Returns an array of all the glyph ids that are used to make up this glyph. That
-is all the compounds and their references and so on. If this glyph is not a
-compound, then returns an empty array
-
-=cut
-
-sub get_refs
-{
- my ($self) = @_;
- my (@res, $g);
-
- $self->read_dat;
- return unless ($self->{'numberOfContours'} < 0);
- foreach $g (@{$self->{'comps'}})
- {
- my (@list) = $self->{' PARENT'}{'loca'}{'glyphs'}[$g->{'glyph'}]->get_points;
- push (@res, $g->{'glyph'});
- push (@res, @list) if ($list[0]);
- }
- return @res;
-}
-
-1;
-
-=head1 BUGS
-
-=over 4
-
-=item *
-
-The instance variables used here are somewhat clunky and inconsistent with
-the other tables.
-
-=item *
-
-C<update> doesn't re-calculate the bounding box or C<numberOfContours>.
-
-=back
-
-=head1 AUTHOR
-
-Martin Hosken Martin_Hosken at sil.org. See L<Font::TTF::Font> for copyright and
-licensing.
-
-=cut
+package Font::TTF::Glyph;
+
+=head1 NAME
+
+Font::TTF::Glyph - Holds a single glyph's information
+
+=head1 DESCRIPTION
+
+This is a single glyph description as held in a TT font. On creation only its
+header is read. Thus you can get the bounding box of each glyph without having
+to read all the other information.
+
+=head1 INSTANCE VARIABLES
+
+In addition to the named variables in a glyph header (C<xMin> etc.), there are
+also all capital instance variables for holding working information, mostly
+from the location table.
+
+The standard attributes each glyph has are:
+
+ numberOfContours
+ xMin
+ yMin
+ xMax
+ yMax
+
+There are also other, derived, instance variables for each glyph which are read
+when the whole glyph is read (via C<read_dat>):
+
+=over 4
+
+=item instLen
+
+Number of bytes in the hinting instructions (Warning this variable is deprecated,
+use C<length($g->{'hints'})> instead).
+
+=item hints
+
+The string containing the hinting code for the glyph
+
+=back
+
+In addition there are other attribute like instance variables for simple glyphs:
+
+=over 4
+
+For each contour there is:
+
+=over 4
+
+=item endPoints
+
+An array of endpoints for each contour in the glyph. There are
+C<numberOfContours> contours in a glyph. The number of points in a glyph is
+equal to the highest endpoint of a contour.
+
+=back
+
+There are also a number of arrays indexed by point number
+
+=over 4
+
+=item flags
+
+The flags associated with reading this point. The flags for a point are
+recalculated for a point when it is C<update>d. Thus the flags are not very
+useful. The only important bit is bit 0 which indicates whether the point is
+an 'on' curve point, or an 'off' curve point.
+
+=item x
+
+The absolute x co-ordinate of the point.
+
+=item y
+
+The absolute y co-ordinate of the point
+
+=back
+
+=back
+
+For composite glyphs there are other variables
+
+=over 4
+
+=item metric
+
+This holds the component number (not its glyph number) of the component from
+which the metrics for this glyph should be taken.
+
+=item comps
+
+This is an array of hashes for each component. Each hash has a number of
+elements:
+
+=over 4
+
+=item glyph
+
+The glyph number of the glyph which comprises this component of the composite.
+
+=item args
+
+An array of two arguments which may be an x, y co-ordinate or two attachment
+points (one on the base glyph the other on the component). See flags for details.
+
+=item flag
+
+The flag for this component
+
+=item scale
+
+A 4 number array for component scaling. This allows stretching, rotating, etc.
+Note that scaling applies to placement co-ordinates (rather than attachment points)
+before locating rather than after.
+
+=back
+
+=item numPoints
+
+This is a generated value which contains the number of components read in for this
+compound glyph.
+
+=back
+
+The private instance variables are:
+
+=over 4
+
+=item INFILE (P)
+
+The input file form which to read any information
+
+=item LOC (P)
+
+Location relative to the start of the glyf table in the read file
+
+=item BASE (P)
+
+The location of the glyf table in the read file
+
+=item LEN (P)
+
+This is the number of bytes required by the glyph. It should be kept up to date
+by calling the C<update> method whenever any of the glyph content changes.
+
+=item OUTLOC (P)
+
+Location relative to the start of the glyf table. This variable is only active
+whilst the output process is going on. It is used to inform the location table
+where the glyph's location is, since the glyf table is output before the loca
+table due to alphabetical ordering.
+
+=item OUTLEN (P)
+
+This indicates the length of the glyph data when it is output. This more
+accurately reflects the internal memory form than the C<LEN> variable which
+only reflects the read file length. The C<OUTLEN> variable is only set after
+calling C<out> or C<out_dat>.
+
+=back
+
+=head2 Editing
+
+If you want to edit a glyph in some way, then you should read_dat the glyph, then
+make your changes and then update the glyph or set the $g->{' isdirty'} variable.
+It is the application's duty to ensure that the following instance variables are
+correct, from which update will calculate the rest, including the bounding box
+information.
+
+ numPoints
+ numberOfContours
+ endPoints
+ x, y, flags (only flags bit 0)
+ instLen
+ hints
+
+For components, the numPoints, x, y, endPoints & flags are not required but
+the following information is required for each component.
+
+ flag (bits 2, 10, 11, 12)
+ glyph
+ args
+ scale
+ metric (glyph instance variable)
+
+
+=head1 METHODS
+
+=cut
+
+use strict;
+use vars qw(%fields @field_info);
+use Font::TTF::Utils;
+use Font::TTF::Table;
+
+ at field_info = (
+ 'numberOfContours' => 's',
+ 'xMin' => 's',
+ 'yMin' => 's',
+ 'xMax' => 's',
+ 'yMax' => 's');
+
+sub init
+{
+ my ($k, $v, $c, $i);
+ for ($i = 0; $i < $#field_info; $i += 2)
+ {
+ ($k, $v, $c) = TTF_Init_Fields($field_info[$i], $c, $field_info[$i + 1]);
+ next unless defined $k && $k ne "";
+ $fields{$k} = $v;
+ }
+}
+
+
+=head1 Font::TTF::Glyph->new(%parms)
+
+Creates a new glyph setting various instance variables
+
+=cut
+
+sub new
+{
+ my ($class, %parms) = @_;
+ my ($self) = {};
+ my ($p);
+
+ bless $self, $class;
+ foreach $p (keys %parms)
+ { $self->{" $p"} = $parms{$p}; }
+ init unless defined $fields{'xMin'};
+ $self;
+}
+
+
+=head2 $g->read
+
+Reads the header component of the glyph (bounding box, etc.) and also the
+glyph content, but into a data field rather than breaking it down into
+its constituent structures. Use read_dat for this.
+
+=cut
+
+sub read
+{
+ my ($self) = @_;
+ my ($fh) = $self->{' INFILE'};
+ my ($dat);
+
+ return $self if $self->{' read'};
+ $self->{' read'} = 1;
+ $fh->seek($self->{' LOC'} + $self->{' BASE'}, 0);
+ $fh->read($self->{' DAT'}, $self->{' LEN'});
+ TTF_Read_Fields($self, $self->{' DAT'}, \%fields);
+ $self;
+}
+
+
+=head2 $g->read_dat
+
+Reads the contents of the glyph (components and curves, etc.) from the memory
+store C<DAT> into structures within the object. Then, to indicate where the
+master form of the data is, it deletes the C<DAT> instance variable.
+
+=cut
+
+sub read_dat
+{
+ my ($self) = @_;
+ my ($dat, $num, $max, $i, $flag, $len, $val, $val1, $fp);
+
+ return $self if $self->{' read'} > 1;
+ $self->read unless $self->{' read'};
+ $dat = $self->{' DAT'};
+ $fp = 10;
+ $num = $self->{'numberOfContours'};
+ if ($num > 0)
+ {
+ $self->{'endPoints'} = [unpack("n*", substr($dat, $fp, $num << 1))];
+ $fp += $num << 1;
+ $max = 0;
+ foreach (@{$self->{'endPoints'}})
+ { $max = $_ if $_ > $max; }
+ $max++;
+ $self->{'numPoints'} = $max;
+ $self->{'instLen'} = unpack("n", substr($dat, $fp));
+ $self->{'hints'} = substr($dat, $fp + 2, $self->{'instLen'});
+ $fp += 2 + $self->{'instLen'};
+# read the flags array
+ for ($i = 0; $i < $max; $i++)
+ {
+ $flag = unpack("C", substr($dat, $fp++));
+ $self->{'flags'}[$i] = $flag;
+ if ($flag & 8)
+ {
+ $len = unpack("C", substr($dat, $fp++));
+ while ($len-- > 0)
+ {
+ $i++;
+ $self->{'flags'}[$i] = $flag;
+ }
+ }
+ }
+#read the x array
+ for ($i = 0; $i < $max; $i++)
+ {
+ $flag = $self->{'flags'}[$i];
+ if ($flag & 2)
+ {
+ $val = unpack("C", substr($dat, $fp++));
+ $val = -$val unless ($flag & 16);
+ } elsif ($flag & 16)
+ { $val = 0; }
+ else
+ {
+ $val = TTF_Unpack("s", substr($dat, $fp));
+ $fp += 2;
+ }
+ $self->{'x'}[$i] = $i == 0 ? $val : $self->{'x'}[$i - 1] + $val;
+ }
+#read the y array
+ for ($i = 0; $i < $max; $i++)
+ {
+ $flag = $self->{'flags'}[$i];
+ if ($flag & 4)
+ {
+ $val = unpack("C", substr($dat, $fp++));
+ $val = -$val unless ($flag & 32);
+ } elsif ($flag & 32)
+ { $val = 0; }
+ else
+ {
+ $val = TTF_Unpack("s", substr($dat, $fp));
+ $fp += 2;
+ }
+ $self->{'y'}[$i] = $i == 0 ? $val : $self->{'y'}[$i - 1] + $val;
+ }
+ }
+
+# compound glyph
+ elsif ($num < 0)
+ {
+ $flag = 1 << 5; # cheat to get the loop going
+ for ($i = 0; $flag & 32; $i++)
+ {
+ ($flag, $self->{'comps'}[$i]{'glyph'}) = unpack("n2", substr($dat, $fp));
+ $fp += 4;
+ $self->{'comps'}[$i]{'flag'} = $flag;
+ if ($flag & 1) # ARGS1_AND_2_ARE_WORDS
+ {
+ $self->{'comps'}[$i]{'args'} = [TTF_Unpack("s2", substr($dat, $fp))];
+ $fp += 4;
+ } else
+ {
+ $self->{'comps'}[$i]{'args'} = [unpack("c2", substr($dat, $fp))];
+ $fp += 2;
+ }
+
+ if ($flag & 8)
+ {
+ $val = TTF_Unpack("F", substr($dat, $fp));
+ $fp += 2;
+ $self->{'comps'}[$i]{'scale'} = [$val, 0, 0, $val];
+ } elsif ($flag & 64)
+ {
+ ($val, $val1) = TTF_Unpack("F2", substr($dat, $fp));
+ $fp += 4;
+ $self->{'comps'}[$i]{'scale'} = [$val, 0, 0, $val1];
+ } elsif ($flag & 128)
+ {
+ $self->{'comps'}[$i]{'scale'} = [TTF_Unpack("F4", substr($dat, $fp))];
+ $fp += 8;
+ }
+ $self->{'metric'} = $i if ($flag & 512);
+ }
+ $self->{'numPoints'} = $i;
+ if ($flag & 256) # HAVE_INSTRUCTIONS
+ {
+ $self->{'instLen'} = unpack("n", substr($dat, $fp));
+ $self->{'hints'} = substr($dat, $fp + 2, $self->{'instLen'});
+ $fp += 2 + $self->{'instLen'};
+ }
+ }
+ return undef if ($fp > length($dat));
+ $self->{' read'} = 2;
+ $self;
+}
+
+
+=head2 $g->out($fh)
+
+Writes the glyph data to outfile
+
+=cut
+
+sub out
+{
+ my ($self, $fh) = @_;
+
+ $self->read unless $self->{' read'};
+ $self->update if $self->{' isDirty'};
+ $fh->print($self->{' DAT'});
+ $self->{' OUTLEN'} = length($self->{' DAT'});
+ $self;
+}
+
+
+=head2 $g->out_xml($context, $depth)
+
+Outputs an XML description of the glyph
+
+=cut
+
+sub out_xml
+{
+ my ($self, $context, $depth) = @_;
+ my ($addr) = ($self =~ m/\((.+)\)$/o);
+ my ($k, $ndepth);
+
+ if ($context->{'addresses'}{$addr})
+ {
+ $context->{'fh'}->printf("%s<glyph gid='%s' id_ref='%s'/>\n", $depth, $context->{'gid'}, $addr);
+ return $self;
+ }
+ else
+ {
+ $context->{'fh'}->printf("%s<glyph gid='%s' id='%s'>\n", $depth, $context->{'gid'}, $addr);
+ }
+
+ $ndepth = $depth . $context->{'indent'};
+ $self->read_dat;
+ foreach $k (sort grep {$_ !~ m/^\s/o} keys %{$self})
+ {
+ $self->XML_element($context, $ndepth, $k, $self->{$k});
+ }
+ $context->{'fh'}->print("$depth</glyph>\n");
+ delete $context->{'done_points'};
+ $self;
+}
+
+
+sub XML_element
+{
+ my ($self, $context, $depth, $key, $val) = @_;
+ my ($fh) = $context->{'fh'};
+ my ($dind) = $depth . $context->{'indent'};
+ my ($i);
+
+ if ($self->{'numberOfContours'} >= 0 && ($key eq 'x' || $key eq 'y' || $key eq 'flags'))
+ {
+ return $self if ($context->{'done_points'});
+ $context->{'done_points'} = 1;
+
+ $fh->print("$depth<points>\n");
+ for ($i = 0; $i <= $#{$self->{'flags'}}; $i++)
+ { $fh->printf("%s<point x='%s' y='%s' flags='0x%02X'/>\n", $dind,
+ $self->{'x'}[$i], $self->{'y'}[$i], $self->{'flags'}[$i]); }
+ $fh->print("$depth</points>\n");
+ }
+ elsif ($key eq 'hints')
+ {
+ my ($dat);
+ $fh->print("$depth<hints>\n");
+# Font::TTF::Utils::XML_hexdump($context, $depth . $context->{'indent'}, $self->{'hints'});
+ $dat = Font::TTF::Utils::XML_binhint($self->{'hints'});
+ $dat =~ s/\n(?!$)/\n$depth$context->{'indent'}/mg;
+ $fh->print("$depth$context->{'indent'}$dat");
+ $fh->print("$depth</hints>\n");
+ }
+ else
+ { return Font::TTF::Table::XML_element(@_); }
+
+ $self;
+}
+
+
+=head2 $g->update
+
+Generates a C<$self->{'DAT'}> from the internal structures, if the data has
+been read into structures in the first place. If you are building a glyph
+from scratch you will need to set the instance variable C<' read'> to 2 (or
+something > 1) for the update to work.
+
+=cut
+
+sub update
+{
+ my ($self) = @_;
+ my ($dat, $loc, $len, $flag, $x, $y, $i, $comp, $num);
+
+ return $self unless (defined $self->{' read'} && $self->{' read'} > 1);
+ $self->update_bbox;
+ $self->{' DAT'} = TTF_Out_Fields($self, \%fields, 10);
+ $num = $self->{'numberOfContours'};
+ if ($num > 0)
+ {
+ $self->{' DAT'} .= pack("n*", @{$self->{'endPoints'}});
+ $len = $self->{'instLen'};
+ $self->{' DAT'} .= pack("n", $len);
+ $self->{' DAT'} .= pack("a" . $len, substr($self->{'hints'}, 0, $len)) if ($len > 0);
+ for ($i = 0; $i < $self->{'numPoints'}; $i++)
+ {
+ $flag = $self->{'flags'}[$i] & 1;
+ if ($i == 0)
+ {
+ $x = $self->{'x'}[$i];
+ $y = $self->{'y'}[$i];
+ } else
+ {
+ $x = $self->{'x'}[$i] - $self->{'x'}[$i - 1];
+ $y = $self->{'y'}[$i] - $self->{'y'}[$i - 1];
+ }
+ $flag |= 16 if ($x == 0);
+ $flag |= 32 if ($y == 0);
+ if (($flag & 16) == 0 && $x < 256 && $x > -256)
+ {
+ $flag |= 2;
+ $flag |= 16 if ($x >= 0);
+ }
+ if (($flag & 32) == 0 && $y < 256 && $y > -256)
+ {
+ $flag |= 4;
+ $flag |= 32 if ($y >= 0);
+ }
+ $self->{' DAT'} .= pack("C", $flag); # sorry no repeats
+ $self->{'flags'}[$i] = $flag;
+ }
+ for ($i = 0; $i < $self->{'numPoints'}; $i++)
+ {
+ $flag = $self->{'flags'}[$i];
+ $x = $self->{'x'}[$i] - (($i == 0) ? 0 : $self->{'x'}[$i - 1]);
+ if (($flag & 18) == 0)
+ { $self->{' DAT'} .= TTF_Pack("s", $x); }
+ elsif (($flag & 18) == 18)
+ { $self->{' DAT'} .= pack("C", $x); }
+ elsif (($flag & 18) == 2)
+ { $self->{' DAT'} .= pack("C", -$x); }
+ }
+ for ($i = 0; $i < $self->{'numPoints'}; $i++)
+ {
+ $flag = $self->{'flags'}[$i];
+ $y = $self->{'y'}[$i] - (($i == 0) ? 0 : $self->{'y'}[$i - 1]);
+ if (($flag & 36) == 0)
+ { $self->{' DAT'} .= TTF_Pack("s", $y); }
+ elsif (($flag & 36) == 36)
+ { $self->{' DAT'} .= pack("C", $y); }
+ elsif (($flag & 36) == 4)
+ { $self->{' DAT'} .= pack("C", -$y); }
+ }
+ }
+
+ elsif ($num < 0)
+ {
+ for ($i = 0; $i <= $#{$self->{'comps'}}; $i++)
+ {
+ $comp = $self->{'comps'}[$i];
+ $flag = $comp->{'flag'} & 7158; # bits 2,10,11,12
+ $flag |= 1 unless ($comp->{'args'}[0] > -129 && $comp->{'args'}[0] < 128
+ && $comp->{'args'}[1] > -129 && $comp->{'args'}[1] < 128);
+ if (defined $comp->{'scale'})
+ {
+ if ($comp->{'scale'}[1] == 0 && $comp->{'scale'}[2] == 0)
+ {
+ if ($comp->{'scale'}[0] == $comp->{'scale'}[3])
+ { $flag |= 8 unless ($comp->{'scale'}[0] == 0
+ || abs(abs($comp->{'scale'}[0]) - 1.) < .001); }
+ else
+ { $flag |= 64; }
+ } else
+ { $flag |= 128; }
+ }
+
+ $flag |= 512 if (defined $self->{'metric'} && $self->{'metric'} == $i);
+ if ($i == $#{$self->{'comps'}})
+ { $flag |= 256 if (defined $self->{'instLen'} && $self->{'instLen'} > 0); }
+ else
+ { $flag |= 32; }
+
+ $self->{' DAT'} .= pack("n", $flag);
+ $self->{' DAT'} .= pack("n", $comp->{'glyph'});
+ $comp->{'flag'} = $flag;
+
+ if ($flag & 1)
+ { $self->{' DAT'} .= TTF_Pack("s2", @{$comp->{'args'}}); }
+ else
+ { $self->{' DAT'} .= pack("CC", @{$comp->{'args'}}); }
+
+ if ($flag & 8)
+ { $self->{' DAT'} .= TTF_Pack("F", $comp->{'scale'}[0]); }
+ elsif ($flag & 64)
+ { $self->{' DAT'} .= TTF_Pack("F2", $comp->{'scale'}[0], $comp->{'scale'}[3]); }
+ elsif ($flag & 128)
+ { $self->{' DAT'} .= TTF_Pack("F4", @{$comp->{'scale'}}); }
+ }
+ if (defined $self->{'instLen'} && $self->{'instLen'} > 0)
+ {
+ $len = $self->{'instLen'};
+ $self->{' DAT'} .= pack("n", $len);
+ $self->{' DAT'} .= pack("a" . $len, substr($self->{'hints'}, 0, $len));
+ }
+ }
+ $self->{' DAT'} .= "\000" if (length($self->{' DAT'}) & 1);
+ $self->{' OUTLEN'} = length($self->{' DAT'});
+ $self->{' read'} = 2; # changed from 1 to 2 so we don't read_dat() again
+# we leave numPoints and instLen since maxp stats use this
+ $self;
+}
+
+
+=head2 $g->update_bbox
+
+Updates the bounding box for this glyph according to the points in the glyph
+
+=cut
+
+sub update_bbox
+{
+ my ($self) = @_;
+ my ($num, $maxx, $minx, $maxy, $miny, $i, $comp, $x, $y, $compg);
+
+ return $self unless $self->{' read'} > 1; # only if read_dat done
+ $miny = $minx = 65537; $maxx = $maxy = -65537;
+ $num = $self->{'numberOfContours'};
+ if ($num > 0)
+ {
+ for ($i = 0; $i < $self->{'numPoints'}; $i++)
+ {
+ ($x, $y) = ($self->{'x'}[$i], $self->{'y'}[$i]);
+
+ $maxx = $x if ($x > $maxx);
+ $minx = $x if ($x < $minx);
+ $maxy = $y if ($y > $maxy);
+ $miny = $y if ($y < $miny);
+ }
+ }
+
+ elsif ($num < 0)
+ {
+ foreach $comp (@{$self->{'comps'}})
+ {
+ my ($gnx, $gny, $gxx, $gxy);
+ my ($sxx, $sxy, $syx, $syy);
+
+ $compg = $self->{' PARENT'}{'loca'}{'glyphs'}[$comp->{'glyph'}]->read->update_bbox;
+ ($gnx, $gny, $gxx, $gxy) = @{$compg}{'xMin', 'yMin', 'xMax', 'yMax'};
+ if (defined $comp->{'scale'})
+ {
+ ($sxx, $sxy, $syx, $syy) = @{$comp->{'scale'}};
+ ($gnx, $gny, $gxx, $gxy) = ($gnx*$sxx+$gny*$syx + $comp->{'args'}[0],
+ $gnx*$sxy+$gny*$syy + $comp->{'args'}[1],
+ $gxx*$sxx+$gxy*$syx + $comp->{'args'}[0],
+ $gxx*$sxy+$gxy*$syy + $comp->{'args'}[1]);
+ } elsif ($comp->{'args'}[0] || $comp->{'args'}[1])
+ {
+ $gnx += $comp->{'args'}[0];
+ $gny += $comp->{'args'}[1];
+ $gxx += $comp->{'args'}[0];
+ $gxy += $comp->{'args'}[1];
+ }
+ $maxx = $gxx if $gxx > $maxx;
+ $minx = $gnx if $gnx < $minx;
+ $maxy = $gxy if $gxy > $maxy;
+ $miny = $gny if $gny < $miny;
+ }
+ }
+ $self->{'xMax'} = $maxx;
+ $self->{'xMin'} = $minx;
+ $self->{'yMax'} = $maxy;
+ $self->{'yMin'} = $miny;
+ $self;
+}
+
+
+=head2 $g->maxInfo
+
+Returns lots of information about a glyph so that the C<maxp> table can update
+itself.
+
+=cut
+
+sub maxInfo
+{
+ my ($self) = @_;
+ my (@res, $i, @n);
+
+ $self->read_dat; # make sure we've read some data
+ $res[4] = length($self->{'hints'}) if defined $self->{'hints'};
+ if ($self->{'numberOfContours'} > 0)
+ {
+ $res[2] = $res[0] = $self->{'numPoints'};
+ $res[3] = $res[1] = $self->{'numberOfContours'};
+ $res[6] = 1;
+ } elsif ($self->{'numberOfContours'} < 0)
+ {
+ $res[6] = 1;
+ for ($i = 0; $i <= $#{$self->{'comps'}}; $i++)
+ {
+ @n = $self->{' PARENT'}{'loca'}{'glyphs'}[$self->{'comps'}[$i]{'glyph'}]->maxInfo;
+ $res[2] += $n[2] == 0 ? $n[0] : $n[2];
+ $res[3] += $n[3] == 0 ? $n[1] : $n[3];
+ $res[5]++;
+ $res[6] = $n[6] + 1 if ($n[6] >= $res[6]);
+ }
+ }
+ @res;
+}
+
+=head2 $g->empty
+
+Empties the glyph of all information to the level of not having been read.
+Useful for saving memory in apps with many glyphs being read
+
+=cut
+
+sub empty
+{
+ my ($self) = @_;
+ my (%keep) = map {(" $_" => 1)} ('LOC', 'OUTLOC', 'PARENT', 'INFILE', 'BASE',
+ 'OUTLEN', 'LEN');
+ map {delete $self->{$_} unless $keep{$_}} keys %$self;
+
+ $self;
+}
+
+
+=head2 $g->get_points
+
+This method creates point information for a compound glyph. The information is
+stored in the same place as if the glyph was not a compound, but since
+numberOfContours is negative, the glyph is still marked as being a compound
+
+=cut
+
+sub get_points
+{
+ my ($self) = @_;
+ my ($comp, $compg, $nump, $e, $i);
+
+ $self->read_dat;
+ return undef unless ($self->{'numberOfContours'} < 0);
+
+ foreach $comp (@{$self->{'comps'}})
+ {
+ $compg = $self->{' PARENT'}{'loca'}{'glyphs'}[$comp->{'glyph'}]->read;
+ $compg->get_points;
+
+ for ($i = 0; $i < $compg->{'numPoints'}; $i++)
+ {
+ my ($x, $y) = ($compg->{'x'}[$i], $compg->{'y'}[$i]);
+ if (defined $comp->{'scale'})
+ {
+ ($x, $y) = ($x * $comp->{'scale'}[0] + $y * $comp->{'scale'}[2],
+ $x * $comp->{'scale'}[1] + $y * $comp->{'scale'}[3]);
+ }
+ if (defined $comp->{'args'})
+ { ($x, $y) = ($x + $comp->{'args'}[0], $y + $comp->{'args'}[1]); }
+ push (@{$self->{'x'}}, $x);
+ push (@{$self->{'y'}}, $y);
+ }
+ foreach $e (@{$compg->{'endPoints'}})
+ { push (@{$self->{'endPoints'}}, $e + $nump); }
+ $nump += $compg->{'numPoints'};
+ }
+ $self->{'numPoints'} = $nump;
+ $self;
+}
+
+
+=head2 $g->get_refs
+
+Returns an array of all the glyph ids that are used to make up this glyph. That
+is all the compounds and their references and so on. If this glyph is not a
+compound, then returns an empty array
+
+=cut
+
+sub get_refs
+{
+ my ($self) = @_;
+ my (@res, $g);
+
+ $self->read_dat;
+ return unless ($self->{'numberOfContours'} < 0);
+ foreach $g (@{$self->{'comps'}})
+ {
+ my (@list) = $self->{' PARENT'}{'loca'}{'glyphs'}[$g->{'glyph'}]->get_points;
+ push (@res, $g->{'glyph'});
+ push (@res, @list) if ($list[0]);
+ }
+ return @res;
+}
+
+1;
+
+=head1 BUGS
+
+=over 4
+
+=item *
+
+The instance variables used here are somewhat clunky and inconsistent with
+the other tables.
+
+=item *
+
+C<update> doesn't re-calculate the bounding box or C<numberOfContours>.
+
+=back
+
+=head1 AUTHOR
+
+Martin Hosken Martin_Hosken at sil.org. See L<Font::TTF::Font> for copyright and
+licensing.
+
+=cut
Modified: packages/libfont-ttf-perl/trunk/lib/Font/TTF/Hdmx.pm
===================================================================
--- packages/libfont-ttf-perl/trunk/lib/Font/TTF/Hdmx.pm 2006-01-17 02:56:43 UTC (rev 1966)
+++ packages/libfont-ttf-perl/trunk/lib/Font/TTF/Hdmx.pm 2006-01-17 03:07:20 UTC (rev 1967)
@@ -1,149 +1,149 @@
-package Font::TTF::Hdmx;
-
-=head1 NAME
-
-Font::TTF::Hdmx - Horizontal device metrics
-
-=head1 DESCRIPTION
-
-The table consists of an hash of device metric tables indexed by the ppem for
-that subtable. Each subtable consists of an array of advance widths in pixels
-for each glyph at that ppem (horizontally).
-
-=head1 INSTANCE VARIABLES
-
-Individual metrics are accessed using the following referencing:
-
- $f->{'hdmx'}{$ppem}[$glyph_num]
-
-In addition there is one instance variable:
-
-=over 4
-
-=item Num
-
-Number of device tables.
-
-=back
-
-=head2 METHODS
-
-=cut
-
-use strict;
-use vars qw(@ISA);
-
- at ISA = qw(Font::TTF::Table);
-
-
-=head2 $t->read
-
-Reads the table into data structures
-
-=cut
-
-sub read
-{
- my ($self) = @_;
- my ($fh) = $self->{' INFILE'};
- my ($numg, $ppem, $i, $numt, $dat, $len);
-
- $numg = $self->{' PARENT'}{'maxp'}{'numGlyphs'};
- $self->SUPER::read or return $self;
-
- $fh->read($dat, 8);
- ($self->{'Version'}, $numt, $len) = unpack("nnN", $dat);
- $self->{'Num'} = $numt;
-
- for ($i = 0; $i < $numt; $i++)
- {
- $fh->read($dat, $len);
- $ppem = unpack("C", $dat);
- $self->{$ppem} = [unpack("C$numg", substr($dat, 2))];
- }
- $self;
-}
-
-
-=head2 $t->out($fh)
-
-Outputs the device metrics for this font
-
-=cut
-
-sub out
-{
- my ($self, $fh) = @_;
- my ($numg, $i, $pad, $len, $numt, @ppem, $max);
-
- return $self->SUPER::out($fh) unless ($self->{' read'});
-
- $numg = $self->{' PARENT'}{'maxp'}{'numGlyphs'};
- @ppem = grep(/^\d+$/, sort {$a <=> $b} keys %$self);
- $pad = "\000" x (3 - ($numg + 1) % 4);
- $len = $numg + 2 + length($pad);
- $fh->print(pack("nnN", 0, $#ppem + 1, $len));
- for $i (@ppem)
- {
- $max = 0;
- foreach (@{$self->{$i}}[0..($numg - 1)])
- { $max = $_ if $_ > $max; }
- $fh->print(pack("C*", $i, $max, @{$self->{$i}}[0..($numg - 1)]) . $pad);
- }
- $self;
-}
-
-
-=head2 $t->tables_do(&func)
-
-For each subtable it calls &sub($ref, $ppem)
-
-=cut
-
-sub tables_do
-{
- my ($self, $func) = @_;
- my ($i);
-
- foreach $i (grep(/^\d+$/, %$self))
- { &$func($self->{$i}, $i); }
- $self;
-}
-
-
-=head2 $t->XML_element($context, $depth, $key, $value)
-
-Outputs device metrics a little more tidily
-
-=cut
-
-sub XML_element
-{
- my ($self) = shift;
- my ($context, $depth, $key, $value) = @_;
- my ($fh) = $context->{'fh'};
- my ($i);
-
- return $self->SUPER::XML_element(@_) if (ref($value) ne 'ARRAY');
- $fh->print("$depth<metrics ppem='$key'>\n");
- for ($i = 0; $i <= $#{$value}; $i += 25)
- {
- $fh->print("$depth$context->{'indent'}". join(' ', @{$value}[$i .. $i + 24]) . "\n");
- }
- $fh->print("$depth</metrics>\n");
- $self;
-}
-
-1;
-
-=head1 BUGS
-
-None known
-
-=head1 AUTHOR
-
-Martin Hosken Martin_Hosken at sil.org. See L<Font::TTF::Font> for copyright and
-licensing.
-
-=cut
-
+package Font::TTF::Hdmx;
+
+=head1 NAME
+
+Font::TTF::Hdmx - Horizontal device metrics
+
+=head1 DESCRIPTION
+
+The table consists of an hash of device metric tables indexed by the ppem for
+that subtable. Each subtable consists of an array of advance widths in pixels
+for each glyph at that ppem (horizontally).
+
+=head1 INSTANCE VARIABLES
+
+Individual metrics are accessed using the following referencing:
+
+ $f->{'hdmx'}{$ppem}[$glyph_num]
+
+In addition there is one instance variable:
+
+=over 4
+
+=item Num
+
+Number of device tables.
+
+=back
+
+=head2 METHODS
+
+=cut
+
+use strict;
+use vars qw(@ISA);
+
+ at ISA = qw(Font::TTF::Table);
+
+
+=head2 $t->read
+
+Reads the table into data structures
+
+=cut
+
+sub read
+{
+ my ($self) = @_;
+ my ($fh) = $self->{' INFILE'};
+ my ($numg, $ppem, $i, $numt, $dat, $len);
+
+ $numg = $self->{' PARENT'}{'maxp'}{'numGlyphs'};
+ $self->SUPER::read or return $self;
+
+ $fh->read($dat, 8);
+ ($self->{'Version'}, $numt, $len) = unpack("nnN", $dat);
+ $self->{'Num'} = $numt;
+
+ for ($i = 0; $i < $numt; $i++)
+ {
+ $fh->read($dat, $len);
+ $ppem = unpack("C", $dat);
+ $self->{$ppem} = [unpack("C$numg", substr($dat, 2))];
+ }
+ $self;
+}
+
+
+=head2 $t->out($fh)
+
+Outputs the device metrics for this font
+
+=cut
+
+sub out
+{
+ my ($self, $fh) = @_;
+ my ($numg, $i, $pad, $len, $numt, @ppem, $max);
+
+ return $self->SUPER::out($fh) unless ($self->{' read'});
+
+ $numg = $self->{' PARENT'}{'maxp'}{'numGlyphs'};
+ @ppem = grep(/^\d+$/, sort {$a <=> $b} keys %$self);
+ $pad = "\000" x (3 - ($numg + 1) % 4);
+ $len = $numg + 2 + length($pad);
+ $fh->print(pack("nnN", 0, $#ppem + 1, $len));
+ for $i (@ppem)
+ {
+ $max = 0;
+ foreach (@{$self->{$i}}[0..($numg - 1)])
+ { $max = $_ if $_ > $max; }
+ $fh->print(pack("C*", $i, $max, @{$self->{$i}}[0..($numg - 1)]) . $pad);
+ }
+ $self;
+}
+
+
+=head2 $t->tables_do(&func)
+
+For each subtable it calls &sub($ref, $ppem)
+
+=cut
+
+sub tables_do
+{
+ my ($self, $func) = @_;
+ my ($i);
+
+ foreach $i (grep(/^\d+$/, %$self))
+ { &$func($self->{$i}, $i); }
+ $self;
+}
+
+
+=head2 $t->XML_element($context, $depth, $key, $value)
+
+Outputs device metrics a little more tidily
+
+=cut
+
+sub XML_element
+{
+ my ($self) = shift;
+ my ($context, $depth, $key, $value) = @_;
+ my ($fh) = $context->{'fh'};
+ my ($i);
+
+ return $self->SUPER::XML_element(@_) if (ref($value) ne 'ARRAY');
+ $fh->print("$depth<metrics ppem='$key'>\n");
+ for ($i = 0; $i <= $#{$value}; $i += 25)
+ {
+ $fh->print("$depth$context->{'indent'}". join(' ', @{$value}[$i .. $i + 24]) . "\n");
+ }
+ $fh->print("$depth</metrics>\n");
+ $self;
+}
+
+1;
+
+=head1 BUGS
+
+None known
+
+=head1 AUTHOR
+
+Martin Hosken Martin_Hosken at sil.org. See L<Font::TTF::Font> for copyright and
+licensing.
+
+=cut
+
Modified: packages/libfont-ttf-perl/trunk/lib/Font/TTF/Head.pm
===================================================================
--- packages/libfont-ttf-perl/trunk/lib/Font/TTF/Head.pm 2006-01-17 02:56:43 UTC (rev 1966)
+++ packages/libfont-ttf-perl/trunk/lib/Font/TTF/Head.pm 2006-01-17 03:07:20 UTC (rev 1967)
@@ -1,250 +1,250 @@
-package Font::TTF::Head;
-
-=head1 NAME
-
-Font::TTF::Head - The head table for a TTF Font
-
-=head1 DESCRIPTION
-
-This is a very basic table with just instance variables as described in the
-TTF documentation, using the same names. One of the most commonly used is
-C<unitsPerEm>.
-
-=head1 INSTANCE VARIABLES
-
-The C<head> table has no internal instance variables beyond those common to all
-tables and those specified in the standard:
-
- version
- fontRevision
- checkSumAdjustment
- magicNumber
- flags
- unitsPerEm
- created
- modified
- xMin
- yMin
- xMax
- yMax
- macStyle
- lowestRecPPEM
- fontDirectionHint
- indexToLocFormat
- glyphDataFormat
-
-The two dates are held as an array of two unsigned longs (32-bits)
-
-=head1 METHODS
-
-=cut
-
-use strict;
-use vars qw(@ISA %fields @field_info);
-
-require Font::TTF::Table;
-use Font::TTF::Utils;
-
- at ISA = qw(Font::TTF::Table);
- at field_info = (
- 'version' => 'f',
- 'fontRevision' => 'f',
- 'checkSumAdjustment' => 'L',
- 'magicNumber' => 'L',
- 'flags' => 'S',
- 'unitsPerEm' => 'S',
- 'created' => 'L2',
- 'modified' => 'L2',
- 'xMin' => 's',
- 'yMin' => 's',
- 'xMax' => 's',
- 'yMax' => 's',
- 'macStyle' => 'S',
- 'lowestRecPPEM' => 'S',
- 'fontDirectionHint' => 's',
- 'indexToLocFormat' => 's',
- 'glyphDataFormat' => 's');
-
-sub init
-{
- my ($k, $v, $c, $i);
- for ($i = 0; $i < $#field_info; $i += 2)
- {
- ($k, $v, $c) = TTF_Init_Fields($field_info[$i], $c, $field_info[$i + 1]);
- next unless defined $k && $k ne "";
- $fields{$k} = $v;
- }
-}
-
-
-=head2 $t->read
-
-Reads the table into memory thanks to some utility functions
-
-=cut
-
-sub read
-{
- my ($self) = @_;
- my ($dat);
-
- $self->SUPER::read || return $self;
-
- init unless defined $fields{'Ascender'};
- $self->{' INFILE'}->read($dat, 54);
-
- TTF_Read_Fields($self, $dat, \%fields);
- $self;
-}
-
-
-=head2 $t->out($fh)
-
-Writes the table to a file either from memory or by copying. If in memory
-(which is usually) the checkSumAdjustment field is set to 0 as per the default
-if the file checksum is not to be considered.
-
-=cut
-
-sub out
-{
- my ($self, $fh) = @_;
-
- return $self->SUPER::out($fh) unless $self->{' read'}; # this is never true
-# $self->{'checkSumAdjustment'} = 0 unless $self->{' PARENT'}{' wantsig'};
- $fh->print(TTF_Out_Fields($self, \%fields, 54));
- $self;
-}
-
-
-=head2 $t->XML_element($context, $depth, $key, $value)
-
-Handles date process for the XML exporter
-
-=cut
-
-sub XML_element
-{
- my ($self) = shift;
- my ($context, $depth, $key, $value) = @_;
- my ($fh) = $context->{'fh'};
- my ($output, @time);
- my (@month) = qw(JAN FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DEC);
-
- return $self->SUPER::XML_element(@_) unless ($key eq 'created' || $key eq 'modified');
-
- @time = gmtime($self->getdate($key eq 'created'));
- $output = sprintf("%d/%s/%d %d:%d:%d", $time[3], $month[$time[4]], $time[5] + 1900,
- $time[2], $time[1], $time[0]);
- $fh->print("$depth<$key>$output</$key>\n");
- $self;
-}
-
-
-=head2 $t->update
-
-Updates the head table based on the glyph data and the hmtx table
-
-=cut
-
-sub update
-{
- my ($self) = @_;
- my ($num, $i, $loc, $hmtx);
- my ($xMin, $yMin, $xMax, $yMax, $lsbx);
-
- return undef unless ($self->SUPER::update);
-
- $num = $self->{' PARENT'}{'maxp'}{'numGlyphs'};
- return undef unless (defined $self->{' PARENT'}{'hmtx'} && defined $self->{' PARENT'}{'loca'});
- $hmtx = $self->{' PARENT'}{'hmtx'}->read;
-
- $self->{' PARENT'}{'loca'}->update;
- $hmtx->update; # if we updated, then the flags will be set anyway.
- $lsbx = 1;
- for ($i = 0; $i < $num; $i++)
- {
- $loc = $self->{' PARENT'}{'loca'}{'glyphs'}[$i];
- next unless defined $loc;
- $loc->read->update_bbox;
- $xMin = $loc->{'xMin'} if ($loc->{'xMin'} < $xMin || $i == 0);
- $yMin = $loc->{'yMin'} if ($loc->{'yMin'} < $yMin || $i == 0);
- $xMax = $loc->{'xMax'} if ($loc->{'xMax'} > $xMax);
- $yMax = $loc->{'yMax'} if ($loc->{'yMax'} > $yMax);
- $lsbx &= ($loc->{'xMin'} == $hmtx->{'lsb'}[$i]);
- }
- $self->{'xMin'} = $xMin;
- $self->{'yMin'} = $yMin;
- $self->{'xMax'} = $xMax;
- $self->{'yMax'} = $yMax;
- if ($lsbx)
- { $self->{'flags'} |= 2; }
- else
- { $self->{'flags'} &= ~2; }
- $self;
-}
-
-
-=head2 $t->getdate($is_create)
-
-Converts font modification time (or creation time if $is_create is set) to a 32-bit integer as returned
-from time(). Returns undef if the value is out of range, either before the epoch or after the maximum
-storable time.
-
-=cut
-
-sub getdate
-{
- my ($self, $is_create) = @_;
- my ($arr) = $self->{$is_create ? 'created' : 'modified'};
-
- $arr->[1] -= 2082844800; # seconds between 1/Jan/1904 and 1/Jan/1970 (midnight)
- if ($arr->[1] < 0)
- {
- $arr->[1] += 0xFFFFFFF; $arr->[1]++;
- $arr->[0]--;
- }
- return undef if $arr->[0] != 0;
- return $arr->[1];
-}
-
-
-=head2 $t->setdate($time, $is_create)
-
-Sets the time information for modification (or creation time if $is_create is set) according to the 32-bit
-time information.
-
-=cut
-
-sub setdate
-{
- my ($self, $time, $is_create) = @_;
- my (@arr);
-
- $arr[1] = $time;
- if ($arr[1] >= 0x83DA4F80)
- {
- $arr[1] -= 0xFFFFFFFF;
- $arr[1]--;
- $arr[0]++;
- }
- $arr[1] += 2082844800;
- $self->{$is_create ? 'created' : 'modified'} = \@arr;
- $self;
-}
-
-
-1;
-
-
-=head1 BUGS
-
-None known
-
-=head1 AUTHOR
-
-Martin Hosken Martin_Hosken at sil.org. See L<Font::TTF::Font> for copyright and
-licensing.
-
-=cut
-
+package Font::TTF::Head;
+
+=head1 NAME
+
+Font::TTF::Head - The head table for a TTF Font
+
+=head1 DESCRIPTION
+
+This is a very basic table with just instance variables as described in the
+TTF documentation, using the same names. One of the most commonly used is
+C<unitsPerEm>.
+
+=head1 INSTANCE VARIABLES
+
+The C<head> table has no internal instance variables beyond those common to all
+tables and those specified in the standard:
+
+ version
+ fontRevision
+ checkSumAdjustment
+ magicNumber
+ flags
+ unitsPerEm
+ created
+ modified
+ xMin
+ yMin
+ xMax
+ yMax
+ macStyle
+ lowestRecPPEM
+ fontDirectionHint
+ indexToLocFormat
+ glyphDataFormat
+
+The two dates are held as an array of two unsigned longs (32-bits)
+
+=head1 METHODS
+
+=cut
+
+use strict;
+use vars qw(@ISA %fields @field_info);
+
+require Font::TTF::Table;
+use Font::TTF::Utils;
+
+ at ISA = qw(Font::TTF::Table);
+ at field_info = (
+ 'version' => 'f',
+ 'fontRevision' => 'f',
+ 'checkSumAdjustment' => 'L',
+ 'magicNumber' => 'L',
+ 'flags' => 'S',
+ 'unitsPerEm' => 'S',
+ 'created' => 'L2',
+ 'modified' => 'L2',
+ 'xMin' => 's',
+ 'yMin' => 's',
+ 'xMax' => 's',
+ 'yMax' => 's',
+ 'macStyle' => 'S',
+ 'lowestRecPPEM' => 'S',
+ 'fontDirectionHint' => 's',
+ 'indexToLocFormat' => 's',
+ 'glyphDataFormat' => 's');
+
+sub init
+{
+ my ($k, $v, $c, $i);
+ for ($i = 0; $i < $#field_info; $i += 2)
+ {
+ ($k, $v, $c) = TTF_Init_Fields($field_info[$i], $c, $field_info[$i + 1]);
+ next unless defined $k && $k ne "";
+ $fields{$k} = $v;
+ }
+}
+
+
+=head2 $t->read
+
+Reads the table into memory thanks to some utility functions
+
+=cut
+
+sub read
+{
+ my ($self) = @_;
+ my ($dat);
+
+ $self->SUPER::read || return $self;
+
+ init unless defined $fields{'Ascender'};
+ $self->{' INFILE'}->read($dat, 54);
+
+ TTF_Read_Fields($self, $dat, \%fields);
+ $self;
+}
+
+
+=head2 $t->out($fh)
+
+Writes the table to a file either from memory or by copying. If in memory
+(which is usually) the checkSumAdjustment field is set to 0 as per the default
+if the file checksum is not to be considered.
+
+=cut
+
+sub out
+{
+ my ($self, $fh) = @_;
+
+ return $self->SUPER::out($fh) unless $self->{' read'}; # this is never true
+# $self->{'checkSumAdjustment'} = 0 unless $self->{' PARENT'}{' wantsig'};
+ $fh->print(TTF_Out_Fields($self, \%fields, 54));
+ $self;
+}
+
+
+=head2 $t->XML_element($context, $depth, $key, $value)
+
+Handles date process for the XML exporter
+
+=cut
+
+sub XML_element
+{
+ my ($self) = shift;
+ my ($context, $depth, $key, $value) = @_;
+ my ($fh) = $context->{'fh'};
+ my ($output, @time);
+ my (@month) = qw(JAN FEB MAR APR MAY JUN JUL AUG SEP OCT NOV DEC);
+
+ return $self->SUPER::XML_element(@_) unless ($key eq 'created' || $key eq 'modified');
+
+ @time = gmtime($self->getdate($key eq 'created'));
+ $output = sprintf("%d/%s/%d %d:%d:%d", $time[3], $month[$time[4]], $time[5] + 1900,
+ $time[2], $time[1], $time[0]);
+ $fh->print("$depth<$key>$output</$key>\n");
+ $self;
+}
+
+
+=head2 $t->update
+
+Updates the head table based on the glyph data and the hmtx table
+
+=cut
+
+sub update
+{
+ my ($self) = @_;
+ my ($num, $i, $loc, $hmtx);
+ my ($xMin, $yMin, $xMax, $yMax, $lsbx);
+
+ return undef unless ($self->SUPER::update);
+
+ $num = $self->{' PARENT'}{'maxp'}{'numGlyphs'};
+ return undef unless (defined $self->{' PARENT'}{'hmtx'} && defined $self->{' PARENT'}{'loca'});
+ $hmtx = $self->{' PARENT'}{'hmtx'}->read;
+
+ $self->{' PARENT'}{'loca'}->update;
+ $hmtx->update; # if we updated, then the flags will be set anyway.
+ $lsbx = 1;
+ for ($i = 0; $i < $num; $i++)
+ {
+ $loc = $self->{' PARENT'}{'loca'}{'glyphs'}[$i];
+ next unless defined $loc;
+ $loc->read->update_bbox;
+ $xMin = $loc->{'xMin'} if ($loc->{'xMin'} < $xMin || $i == 0);
+ $yMin = $loc->{'yMin'} if ($loc->{'yMin'} < $yMin || $i == 0);
+ $xMax = $loc->{'xMax'} if ($loc->{'xMax'} > $xMax);
+ $yMax = $loc->{'yMax'} if ($loc->{'yMax'} > $yMax);
+ $lsbx &= ($loc->{'xMin'} == $hmtx->{'lsb'}[$i]);
+ }
+ $self->{'xMin'} = $xMin;
+ $self->{'yMin'} = $yMin;
+ $self->{'xMax'} = $xMax;
+ $self->{'yMax'} = $yMax;
+ if ($lsbx)
+ { $self->{'flags'} |= 2; }
+ else
+ { $self->{'flags'} &= ~2; }
+ $self;
+}
+
+
+=head2 $t->getdate($is_create)
+
+Converts font modification time (or creation time if $is_create is set) to a 32-bit integer as returned
+from time(). Returns undef if the value is out of range, either before the epoch or after the maximum
+storable time.
+
+=cut
+
+sub getdate
+{
+ my ($self, $is_create) = @_;
+ my ($arr) = $self->{$is_create ? 'created' : 'modified'};
+
+ $arr->[1] -= 2082844800; # seconds between 1/Jan/1904 and 1/Jan/1970 (midnight)
+ if ($arr->[1] < 0)
+ {
+ $arr->[1] += 0xFFFFFFF; $arr->[1]++;
+ $arr->[0]--;
+ }
+ return undef if $arr->[0] != 0;
+ return $arr->[1];
+}
+
+
+=head2 $t->setdate($time, $is_create)
+
+Sets the time information for modification (or creation time if $is_create is set) according to the 32-bit
+time information.
+
+=cut
+
+sub setdate
+{
+ my ($self, $time, $is_create) = @_;
+ my (@arr);
+
+ $arr[1] = $time;
+ if ($arr[1] >= 0x83DA4F80)
+ {
+ $arr[1] -= 0xFFFFFFFF;
+ $arr[1]--;
+ $arr[0]++;
+ }
+ $arr[1] += 2082844800;
+ $self->{$is_create ? 'created' : 'modified'} = \@arr;
+ $self;
+}
+
+
+1;
+
+
+=head1 BUGS
+
+None known
+
+=head1 AUTHOR
+
+Martin Hosken Martin_Hosken at sil.org. See L<Font::TTF::Font> for copyright and
+licensing.
+
+=cut
+
Modified: packages/libfont-ttf-perl/trunk/lib/Font/TTF/Hhea.pm
===================================================================
--- packages/libfont-ttf-perl/trunk/lib/Font/TTF/Hhea.pm 2006-01-17 02:56:43 UTC (rev 1966)
+++ packages/libfont-ttf-perl/trunk/lib/Font/TTF/Hhea.pm 2006-01-17 03:07:20 UTC (rev 1967)
@@ -1,162 +1,159 @@
-package Font::TTF::Hhea;
-
-=head1 NAME
-
-Font::TTF::Hhea - Horizontal Header table
-
-=head1 DESCRIPTION
-
-This is a simplte table with just standards specified instance variables
-
-=head1 INSTANCE VARIABLES
-
- version
- Ascender
- Descender
- LineGap
- advanceWidthMax
- minLeftSideBearing
- minRightSideBearing
- xMaxExtent
- caretSlopeRise
- caretSlopeRun
- metricDataFormat
- numberOfHMetrics
-
-
-=head1 METHODS
-
-=cut
-
-use strict;
-use vars qw(@ISA %fields @field_info);
-
-require Font::TTF::Table;
-use Font::TTF::Utils;
-
- at ISA = qw(Font::TTF::Table);
- at field_info = (
- 'version' => 'f',
- 'Ascender' => 's',
- 'Descender' => 's',
- 'LineGap' => 's',
- 'advanceWidthMax' => 'S',
- 'minLeftSideBearing' => 's',
- 'minRightSideBearing' => 's',
- 'xMaxExtent' => 's',
- 'caretSlopeRise' => 's',
- 'caretSlopeRun' => 's',
- 'metricDataFormat' => '+10s',
- 'numberOfHMetrics' => 'S');
-
-sub init
-{
- my ($k, $v, $c, $i);
- for ($i = 0; $i < $#field_info; $i += 2)
- {
- ($k, $v, $c) = TTF_Init_Fields($field_info[$i], $c, $field_info[$i + 1]);
- next unless defined $k && $k ne "";
- $fields{$k} = $v;
- }
-}
-
-
-=head2 $t->read
-
-Reads the table into memory as instance variables
-
-=cut
-
-sub read
-{
- my ($self) = @_;
- my ($dat);
-
- $self->SUPER::read or return $self;
- init unless defined $fields{'Ascender'};
- $self->{' INFILE'}->read($dat, 36);
-
- TTF_Read_Fields($self, $dat, \%fields);
- $self;
-}
-
-
-=head2 $t->out($fh)
-
-Writes the table to a file either from memory or by copying.
-
-=cut
-
-sub out
-{
- my ($self, $fh) = @_;
-
- return $self->SUPER::out($fh) unless $self->{' read'};
-
- $self->{'numberOfHMetrics'} = $self->{' PARENT'}{'hmtx'}->numMetrics || $self->{'numberOfHMetrics'};
- $fh->print(TTF_Out_Fields($self, \%fields, 36));
- $self;
-}
-
-
-=head2 $t->update
-
-Updates various parameters in the hhea table from the hmtx table, assuming
-the C<hmtx> table is dirty.
-
-=cut
-
-sub update
-{
- my ($self) = @_;
- my ($hmtx) = $self->{' PARENT'}{'hmtx'};
- my ($glyphs);
- my ($num, $res);
- my ($i, $maw, $mlsb, $mrsb, $mext, $aw, $lsb, $ext);
-
- return undef unless ($self->SUPER::update);
- return undef unless (defined $hmtx && defined $self->{' PARENT'}{'loca'});
-
- $res = $hmtx->read->update;
- $res |= $self->{' PARENT'}{'loca'}->read->update;
- $glyphs = $self->{' PARENT'}{'loca'}{'glyphs'};
- $num = $self->{' PARENT'}{'maxp'}{'numGlyphs'};
-
- return undef unless ($res);
-
- for ($i = 0; $i < $num; $i++)
- {
- $aw = $hmtx->{'advance'}[$i];
- $lsb = $hmtx->{'lsb'}[$i];
- if (defined $glyphs->[$i])
- { $ext = $lsb + $glyphs->[$i]->read->{'xMax'} - $glyphs->[$i]{'xMin'}; }
- else
- { $ext = $aw; }
- $maw = $aw if ($aw > $maw);
- $mlsb = $lsb if ($lsb < $mlsb or $i == 0);
- $mrsb = $aw - $ext if ($aw - $ext < $mrsb or $i == 0);
- $mext = $ext if ($ext > $mext);
- }
- $self->{'advanceWidthMax'} = $maw;
- $self->{'minLeftSideBearing'} = $mlsb;
- $self->{'minRightSideBearing'} = $mrsb;
- $self->{'xMaxExtent'} = $mext;
- $self->{'numberOfHMetrics'} = $hmtx->numMetrics;
- $self;
-}
-
-
-1;
-
-
-=head1 BUGS
-
-None known
-
-=head1 AUTHOR
-
-Martin Hosken Martin_Hosken at sil.org. See L<Font::TTF::Font> for copyright and
-licensing.
-
-=cut
-
+package Font::TTF::Hhea;
+
+=head1 NAME
+
+Font::TTF::Hhea - Horizontal Header table
+
+=head1 DESCRIPTION
+
+This is a simplte table with just standards specified instance variables
+
+=head1 INSTANCE VARIABLES
+
+ version
+ Ascender
+ Descender
+ LineGap
+ advanceWidthMax
+ minLeftSideBearing
+ minRightSideBearing
+ xMaxExtent
+ caretSlopeRise
+ caretSlopeRun
+ metricDataFormat
+ numberOfHMetrics
+
+
+=head1 METHODS
+
+=cut
+
+use strict;
+use vars qw(@ISA %fields @field_info);
+
+require Font::TTF::Table;
+use Font::TTF::Utils;
+
+ at ISA = qw(Font::TTF::Table);
+ at field_info = (
+ 'version' => 'f',
+ 'Ascender' => 's',
+ 'Descender' => 's',
+ 'LineGap' => 's',
+ 'advanceWidthMax' => 'S',
+ 'minLeftSideBearing' => 's',
+ 'minRightSideBearing' => 's',
+ 'xMaxExtent' => 's',
+ 'caretSlopeRise' => 's',
+ 'caretSlopeRun' => 's',
+ 'metricDataFormat' => '+10s',
+ 'numberOfHMetrics' => 'S');
+
+sub init
+{
+ my ($k, $v, $c, $i);
+ for ($i = 0; $i < $#field_info; $i += 2)
+ {
+ ($k, $v, $c) = TTF_Init_Fields($field_info[$i], $c, $field_info[$i + 1]);
+ next unless defined $k && $k ne "";
+ $fields{$k} = $v;
+ }
+}
+
+
+=head2 $t->read
+
+Reads the table into memory as instance variables
+
+=cut
+
+sub read
+{
+ my ($self) = @_;
+ my ($dat);
+
+ $self->SUPER::read or return $self;
+ init unless defined $fields{'Ascender'};
+ $self->{' INFILE'}->read($dat, 36);
+
+ TTF_Read_Fields($self, $dat, \%fields);
+ $self;
+}
+
+
+=head2 $t->out($fh)
+
+Writes the table to a file either from memory or by copying.
+
+=cut
+
+sub out
+{
+ my ($self, $fh) = @_;
+
+ return $self->SUPER::out($fh) unless $self->{' read'};
+
+ $self->{'numberOfHMetrics'} = $self->{' PARENT'}{'hmtx'}->numMetrics || $self->{'numberOfHMetrics'};
+ $fh->print(TTF_Out_Fields($self, \%fields, 36));
+ $self;
+}
+
+
+=head2 $t->update
+
+Updates various parameters in the hhea table from the hmtx table.
+
+=cut
+
+sub update
+{
+ my ($self) = @_;
+ my ($hmtx) = $self->{' PARENT'}{'hmtx'};
+ my ($glyphs);
+ my ($num, $res);
+ my ($i, $maw, $mlsb, $mrsb, $mext, $aw, $lsb, $ext);
+
+ return undef unless ($self->SUPER::update);
+ return undef unless (defined $hmtx && defined $self->{' PARENT'}{'loca'});
+
+ $hmtx->read->update;
+ $self->{' PARENT'}{'loca'}->read->update;
+ $glyphs = $self->{' PARENT'}{'loca'}{'glyphs'};
+ $num = $self->{' PARENT'}{'maxp'}{'numGlyphs'};
+
+ for ($i = 0; $i < $num; $i++)
+ {
+ $aw = $hmtx->{'advance'}[$i];
+ $lsb = $hmtx->{'lsb'}[$i];
+ if (defined $glyphs->[$i])
+ { $ext = $lsb + $glyphs->[$i]->read->{'xMax'} - $glyphs->[$i]{'xMin'}; }
+ else
+ { $ext = $aw; }
+ $maw = $aw if ($aw > $maw);
+ $mlsb = $lsb if ($lsb < $mlsb or $i == 0);
+ $mrsb = $aw - $ext if ($aw - $ext < $mrsb or $i == 0);
+ $mext = $ext if ($ext > $mext);
+ }
+ $self->{'advanceWidthMax'} = $maw;
+ $self->{'minLeftSideBearing'} = $mlsb;
+ $self->{'minRightSideBearing'} = $mrsb;
+ $self->{'xMaxExtent'} = $mext;
+ $self->{'numberOfHMetrics'} = $hmtx->numMetrics;
+ $self;
+}
+
+
+1;
+
+
+=head1 BUGS
+
+None known
+
+=head1 AUTHOR
+
+Martin Hosken Martin_Hosken at sil.org. See L<Font::TTF::Font> for copyright and
+licensing.
+
+=cut
+
Modified: packages/libfont-ttf-perl/trunk/lib/Font/TTF/Hmtx.pm
===================================================================
--- packages/libfont-ttf-perl/trunk/lib/Font/TTF/Hmtx.pm 2006-01-17 02:56:43 UTC (rev 1966)
+++ packages/libfont-ttf-perl/trunk/lib/Font/TTF/Hmtx.pm 2006-01-17 03:07:20 UTC (rev 1967)
@@ -1,214 +1,214 @@
-package Font::TTF::Hmtx;
-
-=head1 NAME
-
-Font::TTF::Hmtx - Horizontal Metrics
-
-=head1 DESCRIPTION
-
-Contains the advance width and left side bearing for each glyph. Given the
-compressability of the data onto disk, this table uses information from
-other tables, and thus must do part of its output during the output of
-other tables
-
-=head1 INSTANCE VARIABLES
-
-The horizontal metrics are kept in two arrays by glyph id. The variable names
-do not start with a space
-
-=over 4
-
-=item advance
-
-An array containing the advance width for each glyph
-
-=item lsb
-
-An array containing the left side bearing for each glyph
-
-=back
-
-=head1 METHODS
-
-=cut
-
-use strict;
-use vars qw(@ISA);
-require Font::TTF::Table;
-
- at ISA = qw(Font::TTF::Table);
-
-
-=head2 $t->read
-
-Reads the horizontal metrics from the TTF file into memory
-
-=cut
-
-sub read
-{
- my ($self) = @_;
- my ($numh, $numg);
-
- $numh = $self->{' PARENT'}{'hhea'}->read->{'numberOfHMetrics'};
- $numg = $self->{' PARENT'}{'maxp'}->read->{'numGlyphs'};
- $self->_read($numg, $numh, "advance", "lsb");
-}
-
-sub _read
-{
- my ($self, $numg, $numh, $tAdv, $tLsb) = @_;
- my ($fh) = $self->{' INFILE'};
- my ($i, $dat);
-
- $self->SUPER::read or return $self;
-
- for ($i = 0; $i < $numh; $i++)
- {
- $fh->read($dat, 4);
- ($self->{$tAdv}[$i], $self->{$tLsb}[$i]) = unpack("nn", $dat);
- $self->{$tLsb}[$i] -= 65536 if ($self->{$tLsb}[$i] >= 32768);
- }
-
- $i--;
- while ($i++ < $numg)
- {
- $fh->read($dat, 2);
- $self->{$tAdv}[$i] = $self->{$tAdv}[$numh - 1];
- $self->{$tLsb}[$i] = unpack("n", $dat);
- $self->{$tLsb}[$i] -= 65536 if ($self->{$tLsb}[$i] >= 32768);
- }
- $self;
-}
-
-=head2 $t->numMetrics
-
-Calculates again the number of long metrics required to store the information
-here. Returns undef if the table has not been read.
-
-=cut
-
-sub numMetrics
-{
- my ($self) = @_;
- my ($numg) = $self->{' PARENT'}{'maxp'}{'numGlyphs'};
- my ($i);
-
- return undef unless $self->{' read'};
-
- for ($i = $numg - 2; $i >= 0; $i--)
- { last if ($self->{'advance'}[$i] != $self->{'advance'}[$i + 1]); }
-
- return $i + 2;
-}
-
-
-=head2 $t->out($fh)
-
-Writes the metrics to a TTF file. Assumes that the C<hhea> has updated the
-numHMetrics from here
-
-=cut
-
-sub out
-{
- my ($self, $fh) = @_;
- my ($numg) = $self->{' PARENT'}{'maxp'}{'numGlyphs'};
- my ($numh) = $self->{' PARENT'}{'hhea'}->read->{'numberOfHMetrics'};
- $self->_out($fh, $numg, $numh, "advance", "lsb");
-}
-
-sub _out
-{
- my ($self, $fh, $numg, $numh, $tAdv, $tLsb) = @_;
- my ($i, $lsb);
-
- return $self->SUPER::out($fh) unless ($self->{' read'});
-
- for ($i = 0; $i < $numg; $i++)
- {
- $lsb = $self->{$tLsb}[$i];
- $lsb += 65536 if $lsb < 0;
- if ($i >= $numh)
- { $fh->print(pack("n", $lsb)); }
- else
- { $fh->print(pack("n2", $self->{$tAdv}[$i], $lsb)); }
- }
- $self;
-}
-
-
-=head2 $t->update
-
-Updates the lsb values from the xMin from the each glyph
-
-=cut
-
-sub update
-{
- my ($self) = @_;
- my ($numg) = $self->{' PARENT'}{'maxp'}{'numGlyphs'};
- my ($i);
-
- return undef unless ($self->SUPER::update);
-# lsb & xMin must always be the same, regardless of any flags!
-# return $self unless ($self->{' PARENT'}{'head'}{'flags'} & 2); # lsb & xMin the same
-
- $self->{' PARENT'}{'loca'}->update;
- for ($i = 0; $i < $numg; $i++)
- {
- my ($g) = $self->{' PARENT'}{'loca'}{'glyphs'}[$i];
- if ($g)
- { $self->{'lsb'}[$i] = $g->read->update_bbox->{'xMin'}; }
- else
- { $self->{'lsb'}[$i] = 0; }
- }
- $self->{' PARENT'}{'head'}{'flags'} |= 2;
- $self;
-}
-
-
-=head2 $t->out_xml($context, $depth)
-
-Outputs the table in XML
-
-=cut
-
-sub out_xml
-{
- my ($self, $context, $depth) = @_;
- my ($fh) = $context->{'fh'};
- my ($numg) = $self->{' PARENT'}{'maxp'}{'numGlyphs'};
- my ($addr) = ($self =~ m/\((.+)\)$/o);
- my ($i);
-
- if ($context->{'addresses'}{$addr})
- {
- $fh->printf("%s<%s id_ref='%s'/>\n", $depth, $context->{'name'}, $addr);
- return $self;
- }
- else
- { $fh->printf("%s<%s id='%s'>\n", $depth, $context->{'name'}, $addr); }
-
- $self->read;
-
- for ($i = 0; $i < $numg; $i++)
- { $fh->print("$depth$context->{'indent'}<width adv='$self->{'advance'}[$i]' lsb='$self->{'lsb'}[$i]'/>\n"); }
-
- $fh->print("$depth</$context->{'name'}>\n");
- $self;
-}
-
-1;
-
-=head1 BUGS
-
-None known
-
-=head1 AUTHOR
-
-Martin Hosken Martin_Hosken at sil.org. See L<Font::TTF::Font> for copyright and
-licensing.
-
-=cut
-
+package Font::TTF::Hmtx;
+
+=head1 NAME
+
+Font::TTF::Hmtx - Horizontal Metrics
+
+=head1 DESCRIPTION
+
+Contains the advance width and left side bearing for each glyph. Given the
+compressability of the data onto disk, this table uses information from
+other tables, and thus must do part of its output during the output of
+other tables
+
+=head1 INSTANCE VARIABLES
+
+The horizontal metrics are kept in two arrays by glyph id. The variable names
+do not start with a space
+
+=over 4
+
+=item advance
+
+An array containing the advance width for each glyph
+
+=item lsb
+
+An array containing the left side bearing for each glyph
+
+=back
+
+=head1 METHODS
+
+=cut
+
+use strict;
+use vars qw(@ISA);
+require Font::TTF::Table;
+
+ at ISA = qw(Font::TTF::Table);
+
+
+=head2 $t->read
+
+Reads the horizontal metrics from the TTF file into memory
+
+=cut
+
+sub read
+{
+ my ($self) = @_;
+ my ($numh, $numg);
+
+ $numh = $self->{' PARENT'}{'hhea'}->read->{'numberOfHMetrics'};
+ $numg = $self->{' PARENT'}{'maxp'}->read->{'numGlyphs'};
+ $self->_read($numg, $numh, "advance", "lsb");
+}
+
+sub _read
+{
+ my ($self, $numg, $numh, $tAdv, $tLsb) = @_;
+ my ($fh) = $self->{' INFILE'};
+ my ($i, $dat);
+
+ $self->SUPER::read or return $self;
+
+ for ($i = 0; $i < $numh; $i++)
+ {
+ $fh->read($dat, 4);
+ ($self->{$tAdv}[$i], $self->{$tLsb}[$i]) = unpack("nn", $dat);
+ $self->{$tLsb}[$i] -= 65536 if ($self->{$tLsb}[$i] >= 32768);
+ }
+
+ $i--;
+ while ($i++ < $numg)
+ {
+ $fh->read($dat, 2);
+ $self->{$tAdv}[$i] = $self->{$tAdv}[$numh - 1];
+ $self->{$tLsb}[$i] = unpack("n", $dat);
+ $self->{$tLsb}[$i] -= 65536 if ($self->{$tLsb}[$i] >= 32768);
+ }
+ $self;
+}
+
+=head2 $t->numMetrics
+
+Calculates again the number of long metrics required to store the information
+here. Returns undef if the table has not been read.
+
+=cut
+
+sub numMetrics
+{
+ my ($self) = @_;
+ my ($numg) = $self->{' PARENT'}{'maxp'}{'numGlyphs'};
+ my ($i);
+
+ return undef unless $self->{' read'};
+
+ for ($i = $numg - 2; $i >= 0; $i--)
+ { last if ($self->{'advance'}[$i] != $self->{'advance'}[$i + 1]); }
+
+ return $i + 2;
+}
+
+
+=head2 $t->out($fh)
+
+Writes the metrics to a TTF file. Assumes that the C<hhea> has updated the
+numHMetrics from here
+
+=cut
+
+sub out
+{
+ my ($self, $fh) = @_;
+ my ($numg) = $self->{' PARENT'}{'maxp'}{'numGlyphs'};
+ my ($numh) = $self->{' PARENT'}{'hhea'}->read->{'numberOfHMetrics'};
+ $self->_out($fh, $numg, $numh, "advance", "lsb");
+}
+
+sub _out
+{
+ my ($self, $fh, $numg, $numh, $tAdv, $tLsb) = @_;
+ my ($i, $lsb);
+
+ return $self->SUPER::out($fh) unless ($self->{' read'});
+
+ for ($i = 0; $i < $numg; $i++)
+ {
+ $lsb = $self->{$tLsb}[$i];
+ $lsb += 65536 if $lsb < 0;
+ if ($i >= $numh)
+ { $fh->print(pack("n", $lsb)); }
+ else
+ { $fh->print(pack("n2", $self->{$tAdv}[$i], $lsb)); }
+ }
+ $self;
+}
+
+
+=head2 $t->update
+
+Updates the lsb values from the xMin from the each glyph
+
+=cut
+
+sub update
+{
+ my ($self) = @_;
+ my ($numg) = $self->{' PARENT'}{'maxp'}{'numGlyphs'};
+ my ($i);
+
+ return undef unless ($self->SUPER::update);
+# lsb & xMin must always be the same, regardless of any flags!
+# return $self unless ($self->{' PARENT'}{'head'}{'flags'} & 2); # lsb & xMin the same
+
+ $self->{' PARENT'}{'loca'}->update;
+ for ($i = 0; $i < $numg; $i++)
+ {
+ my ($g) = $self->{' PARENT'}{'loca'}{'glyphs'}[$i];
+ if ($g)
+ { $self->{'lsb'}[$i] = $g->read->update_bbox->{'xMin'}; }
+ else
+ { $self->{'lsb'}[$i] = 0; }
+ }
+ $self->{' PARENT'}{'head'}{'flags'} |= 2;
+ $self;
+}
+
+
+=head2 $t->out_xml($context, $depth)
+
+Outputs the table in XML
+
+=cut
+
+sub out_xml
+{
+ my ($self, $context, $depth) = @_;
+ my ($fh) = $context->{'fh'};
+ my ($numg) = $self->{' PARENT'}{'maxp'}{'numGlyphs'};
+ my ($addr) = ($self =~ m/\((.+)\)$/o);
+ my ($i);
+
+ if ($context->{'addresses'}{$addr})
+ {
+ $fh->printf("%s<%s id_ref='%s'/>\n", $depth, $context->{'name'}, $addr);
+ return $self;
+ }
+ else
+ { $fh->printf("%s<%s id='%s'>\n", $depth, $context->{'name'}, $addr); }
+
+ $self->read;
+
+ for ($i = 0; $i < $numg; $i++)
+ { $fh->print("$depth$context->{'indent'}<width adv='$self->{'advance'}[$i]' lsb='$self->{'lsb'}[$i]'/>\n"); }
+
+ $fh->print("$depth</$context->{'name'}>\n");
+ $self;
+}
+
+1;
+
+=head1 BUGS
+
+None known
+
+=head1 AUTHOR
+
+Martin Hosken Martin_Hosken at sil.org. See L<Font::TTF::Font> for copyright and
+licensing.
+
+=cut
+
Modified: packages/libfont-ttf-perl/trunk/lib/Font/TTF/Kern/ClassArray.pm
===================================================================
--- packages/libfont-ttf-perl/trunk/lib/Font/TTF/Kern/ClassArray.pm 2006-01-17 02:56:43 UTC (rev 1966)
+++ packages/libfont-ttf-perl/trunk/lib/Font/TTF/Kern/ClassArray.pm 2006-01-17 03:07:20 UTC (rev 1967)
@@ -1,152 +1,153 @@
-package Font::TTF::Kern::ClassArray;
-
-=head1 NAME
-
-Font::TTF::Kern::ClassArray
-
-=head1 METHODS
-
-=cut
-
-use strict;
-use vars qw(@ISA);
-use Font::TTF::Utils;
-use Font::TTF::AATutils;
-
- at ISA = qw(Font::TTF::Kern::Subtable);
-
-sub new
-{
- my ($class) = @_;
- my ($self) = {};
-
- $class = ref($class) || $class;
- bless $self, $class;
-}
-
-=head2 $t->read
-
-Reads the table into memory
-
-=cut
-
-sub read
-{
- my ($self, $fh) = @_;
-
- my $subtableStart = $fh->tell() - 8;
- my $dat;
- $fh->read($dat, 8);
- my ($rowWidth, $leftClassTable, $rightClassTable, $array) = unpack("nnnn", $dat);
-
- $fh->seek($subtableStart + $leftClassTable, IO::File::SEEK_SET);
- $fh->read($dat, 4);
- my ($firstGlyph, $nGlyphs) = unpack("nn", $dat);
- $fh->read($dat, $nGlyphs * 2);
- my $leftClasses = [];
- foreach (TTF_Unpack("S*", $dat)) {
- push @{$leftClasses->[($_ - $array) / $rowWidth]}, $firstGlyph++;
- }
-
- $fh->seek($subtableStart + $rightClassTable, IO::File::SEEK_SET);
- $fh->read($dat, 4);
- ($firstGlyph, $nGlyphs) = unpack("nn", $dat);
- $fh->read($dat, $nGlyphs * 2);
- my $rightClasses = [];
- foreach (TTF_Unpack("S*", $dat)) {
- push @{$rightClasses->[$_ / 2]}, $firstGlyph++;
- }
-
- $fh->seek($subtableStart + $array, IO::File::SEEK_SET);
- $fh->read($dat, $self->{'length'} - $array);
-
- my $offset = 0;
- my $kernArray = [];
- while ($offset < length($dat)) {
- push @$kernArray, [ TTF_Unpack("s*", substr($dat, $offset, $rowWidth)) ];
- $offset += $rowWidth;
- }
-
- $self->{'leftClasses'} = $leftClasses;
- $self->{'rightClasses'} = $rightClasses;
- $self->{'kernArray'} = $kernArray;
-
- $fh->seek($subtableStart + $self->{'length'}, IO::File::SEEK_SET);
-
- $self;
-}
-
-=head2 $t->out_sub($fh)
-
-Writes the table to a file
-
-=cut
-
-sub out_sub
-{
-}
-
-=head2 $t->print($fh)
-
-Prints a human-readable representation of the table
-
-=cut
-
-sub print
-{
- my ($self, $fh) = @_;
-
- my $post = $self->post();
-
- $fh = 'STDOUT' unless defined $fh;
-
-
-}
-
-sub dumpXML
-{
- my ($self, $fh) = @_;
- my $post = $self->post();
-
- $fh = 'STDOUT' unless defined $fh;
- $fh->printf("<leftClasses>\n");
- $self->dumpClasses($self->{'leftClasses'}, $fh);
- $fh->printf("</leftClasses>\n");
-
- $fh->printf("<rightClasses>\n");
- $self->dumpClasses($self->{'rightClasses'}, $fh);
- $fh->printf("</rightClasses>\n");
-
- $fh->printf("<kernArray>\n");
- my $kernArray = $self->{'kernArray'};
- foreach (0 .. $#$kernArray) {
- $fh->printf("<row index=\"%s\">\n", $_);
- my $row = $kernArray->[$_];
- foreach (0 .. $#$row) {
- $fh->printf("<val index=\"%s\" v=\"%s\"/>\n", $_, $row->[$_]);
- }
- $fh->printf("</row>\n");
- }
- $fh->printf("</kernArray>\n");
-}
-
-sub type
-{
- return 'kernClassArray';
-}
-
-
-
-1;
-
-=head1 BUGS
-
-None known
-
-=head1 AUTHOR
-
-Jonathan Kew L<Jonathan_Kew at sil.org>. See L<Font::TTF::Font> for copyright and
-licensing.
-
-=cut
-
+package Font::TTF::Kern::ClassArray;
+
+=head1 NAME
+
+Font::TTF::Kern::ClassArray
+
+=head1 METHODS
+
+=cut
+
+use strict;
+use vars qw(@ISA);
+use Font::TTF::Utils;
+use Font::TTF::AATutils;
+use IO::File;
+
+ at ISA = qw(Font::TTF::Kern::Subtable);
+
+sub new
+{
+ my ($class) = @_;
+ my ($self) = {};
+
+ $class = ref($class) || $class;
+ bless $self, $class;
+}
+
+=head2 $t->read
+
+Reads the table into memory
+
+=cut
+
+sub read
+{
+ my ($self, $fh) = @_;
+
+ my $subtableStart = $fh->tell() - 8;
+ my $dat;
+ $fh->read($dat, 8);
+ my ($rowWidth, $leftClassTable, $rightClassTable, $array) = unpack("nnnn", $dat);
+
+ $fh->seek($subtableStart + $leftClassTable, IO::File::SEEK_SET);
+ $fh->read($dat, 4);
+ my ($firstGlyph, $nGlyphs) = unpack("nn", $dat);
+ $fh->read($dat, $nGlyphs * 2);
+ my $leftClasses = [];
+ foreach (TTF_Unpack("S*", $dat)) {
+ push @{$leftClasses->[($_ - $array) / $rowWidth]}, $firstGlyph++;
+ }
+
+ $fh->seek($subtableStart + $rightClassTable, IO::File::SEEK_SET);
+ $fh->read($dat, 4);
+ ($firstGlyph, $nGlyphs) = unpack("nn", $dat);
+ $fh->read($dat, $nGlyphs * 2);
+ my $rightClasses = [];
+ foreach (TTF_Unpack("S*", $dat)) {
+ push @{$rightClasses->[$_ / 2]}, $firstGlyph++;
+ }
+
+ $fh->seek($subtableStart + $array, IO::File::SEEK_SET);
+ $fh->read($dat, $self->{'length'} - $array);
+
+ my $offset = 0;
+ my $kernArray = [];
+ while ($offset < length($dat)) {
+ push @$kernArray, [ TTF_Unpack("s*", substr($dat, $offset, $rowWidth)) ];
+ $offset += $rowWidth;
+ }
+
+ $self->{'leftClasses'} = $leftClasses;
+ $self->{'rightClasses'} = $rightClasses;
+ $self->{'kernArray'} = $kernArray;
+
+ $fh->seek($subtableStart + $self->{'length'}, IO::File::SEEK_SET);
+
+ $self;
+}
+
+=head2 $t->out_sub($fh)
+
+Writes the table to a file
+
+=cut
+
+sub out_sub
+{
+}
+
+=head2 $t->print($fh)
+
+Prints a human-readable representation of the table
+
+=cut
+
+sub print
+{
+ my ($self, $fh) = @_;
+
+ my $post = $self->post();
+
+ $fh = 'STDOUT' unless defined $fh;
+
+
+}
+
+sub dumpXML
+{
+ my ($self, $fh) = @_;
+ my $post = $self->post();
+
+ $fh = 'STDOUT' unless defined $fh;
+ $fh->printf("<leftClasses>\n");
+ $self->dumpClasses($self->{'leftClasses'}, $fh);
+ $fh->printf("</leftClasses>\n");
+
+ $fh->printf("<rightClasses>\n");
+ $self->dumpClasses($self->{'rightClasses'}, $fh);
+ $fh->printf("</rightClasses>\n");
+
+ $fh->printf("<kernArray>\n");
+ my $kernArray = $self->{'kernArray'};
+ foreach (0 .. $#$kernArray) {
+ $fh->printf("<row index=\"%s\">\n", $_);
+ my $row = $kernArray->[$_];
+ foreach (0 .. $#$row) {
+ $fh->printf("<val index=\"%s\" v=\"%s\"/>\n", $_, $row->[$_]);
+ }
+ $fh->printf("</row>\n");
+ }
+ $fh->printf("</kernArray>\n");
+}
+
+sub type
+{
+ return 'kernClassArray';
+}
+
+
+
+1;
+
+=head1 BUGS
+
+None known
+
+=head1 AUTHOR
+
+Jonathan Kew L<Jonathan_Kew at sil.org>. See L<Font::TTF::Font> for copyright and
+licensing.
+
+=cut
+
Modified: packages/libfont-ttf-perl/trunk/lib/Font/TTF/Kern/CompactClassArray.pm
===================================================================
--- packages/libfont-ttf-perl/trunk/lib/Font/TTF/Kern/CompactClassArray.pm 2006-01-17 02:56:43 UTC (rev 1966)
+++ packages/libfont-ttf-perl/trunk/lib/Font/TTF/Kern/CompactClassArray.pm 2006-01-17 03:07:20 UTC (rev 1967)
@@ -1,93 +1,93 @@
-package Font::TTF::Kern::CompactClassArray;
-
-=head1 NAME
-
-Font::TTF::Kern::CompactClassArray
-
-=head1 METHODS
-
-=cut
-
-use strict;
-use vars qw(@ISA);
-use Font::TTF::Utils;
-use Font::TTF::AATutils;
-
- at ISA = qw(Font::TTF::Kern::Subtable);
-
-sub new
-{
- my ($class) = @_;
- my ($self) = {};
-
- $class = ref($class) || $class;
- bless $self, $class;
-}
-
-=head2 $t->read
-
-Reads the table into memory
-
-=cut
-
-sub read
-{
- my ($self, $fh) = @_;
-
- die "incomplete";
-
- $self;
-}
-
-=head2 $t->out($fh)
-
-Writes the table to a file
-
-=cut
-
-sub out_sub
-{
- my ($self, $fh) = @_;
-
- die "incomplete";
-
- $self;
-}
-
-=head2 $t->print($fh)
-
-Prints a human-readable representation of the table
-
-=cut
-
-sub print
-{
- my ($self, $fh) = @_;
-
- my $post = $self->post();
-
- $fh = 'STDOUT' unless defined $fh;
-
- die "incomplete";
-}
-
-
-sub type
-{
- return 'kernCompactClassArray';
-}
-
-
-1;
-
-=head1 BUGS
-
-None known
-
-=head1 AUTHOR
-
-Jonathan Kew L<Jonathan_Kew at sil.org>. See L<Font::TTF::Font> for copyright and
-licensing.
-
-=cut
-
+package Font::TTF::Kern::CompactClassArray;
+
+=head1 NAME
+
+Font::TTF::Kern::CompactClassArray
+
+=head1 METHODS
+
+=cut
+
+use strict;
+use vars qw(@ISA);
+use Font::TTF::Utils;
+use Font::TTF::AATutils;
+
+ at ISA = qw(Font::TTF::Kern::Subtable);
+
+sub new
+{
+ my ($class) = @_;
+ my ($self) = {};
+
+ $class = ref($class) || $class;
+ bless $self, $class;
+}
+
+=head2 $t->read
+
+Reads the table into memory
+
+=cut
+
+sub read
+{
+ my ($self, $fh) = @_;
+
+ die "incomplete";
+
+ $self;
+}
+
+=head2 $t->out($fh)
+
+Writes the table to a file
+
+=cut
+
+sub out_sub
+{
+ my ($self, $fh) = @_;
+
+ die "incomplete";
+
+ $self;
+}
+
+=head2 $t->print($fh)
+
+Prints a human-readable representation of the table
+
+=cut
+
+sub print
+{
+ my ($self, $fh) = @_;
+
+ my $post = $self->post();
+
+ $fh = 'STDOUT' unless defined $fh;
+
+ die "incomplete";
+}
+
+
+sub type
+{
+ return 'kernCompactClassArray';
+}
+
+
+1;
+
+=head1 BUGS
+
+None known
+
+=head1 AUTHOR
+
+Jonathan Kew L<Jonathan_Kew at sil.org>. See L<Font::TTF::Font> for copyright and
+licensing.
+
+=cut
+
Modified: packages/libfont-ttf-perl/trunk/lib/Font/TTF/Kern/OrderedList.pm
===================================================================
--- packages/libfont-ttf-perl/trunk/lib/Font/TTF/Kern/OrderedList.pm 2006-01-17 02:56:43 UTC (rev 1966)
+++ packages/libfont-ttf-perl/trunk/lib/Font/TTF/Kern/OrderedList.pm 2006-01-17 03:07:20 UTC (rev 1967)
@@ -1,108 +1,108 @@
-package Font::TTF::Kern::OrderedList;
-
-=head1 NAME
-
-Font::TTF::Kern::OrderedList
-
-=head1 METHODS
-
-=cut
-
-use strict;
-use vars qw(@ISA);
-use Font::TTF::Utils;
-use Font::TTF::AATutils;
-
- at ISA = qw(Font::TTF::Kern::Subtable);
-
-sub new
-{
- my ($class, @options) = @_;
- my ($self) = {};
-
- $class = ref($class) || $class;
- bless $self, $class;
-}
-
-=head2 $t->read
-
-Reads the table into memory
-
-=cut
-
-sub read
-{
- my ($self, $fh) = @_;
-
- my $dat;
- $fh->read($dat, 8);
- my ($nPairs, $searchRange, $entrySelector, $rangeShift) = unpack("nnnn", $dat);
-
- my $pairs = [];
- foreach (1 .. $nPairs) {
- $fh->read($dat, 6);
- my ($left, $right, $kern) = TTF_Unpack("SSs", $dat);
- push @$pairs, { 'left' => $left, 'right' => $right, 'kern' => $kern } if $kern != 0;
- }
-
- $self->{'kernPairs'} = $pairs;
-
- $self;
-}
-
-=head2 $t->out_sub($fh)
-
-Writes the table to a file
-
-=cut
-
-sub out_sub
-{
- my ($self, $fh) = @_;
-
- my $pairs = $self->{'kernPairs'};
- $fh->print(pack("nnnn", TTF_bininfo(scalar @$pairs, 6)));
-
- foreach (sort { $a->{'left'} <=> $b->{'left'} or $a->{'right'} <=> $b->{'right'} } @$pairs) {
- $fh->print(TTF_Pack("SSs", $_->{'left'}, $_->{'right'}, $_->{'kern'}));
- }
-}
-
-=head2 $t->print($fh)
-
-Prints a human-readable representation of the table
-
-=cut
-
-sub dumpXML
-{
- my ($self, $fh) = @_;
-
- my $postVal = $self->post()->{'VAL'};
-
- $fh = 'STDOUT' unless defined $fh;
- foreach (@{$self->{'kernPairs'}}) {
- $fh->printf("<pair l=\"%s\" r=\"%s\" v=\"%s\"/>\n", $postVal->[$_->{'left'}], $postVal->[$_->{'right'}], $_->{'kern'});
- }
-}
-
-
-sub type
-{
- return 'kernOrderedList';
-}
-
-
-1;
-
-=head1 BUGS
-
-None known
-
-=head1 AUTHOR
-
-Jonathan Kew L<Jonathan_Kew at sil.org>. See L<Font::TTF::Font> for copyright and
-licensing.
-
-=cut
-
+package Font::TTF::Kern::OrderedList;
+
+=head1 NAME
+
+Font::TTF::Kern::OrderedList
+
+=head1 METHODS
+
+=cut
+
+use strict;
+use vars qw(@ISA);
+use Font::TTF::Utils;
+use Font::TTF::AATutils;
+
+ at ISA = qw(Font::TTF::Kern::Subtable);
+
+sub new
+{
+ my ($class, @options) = @_;
+ my ($self) = {};
+
+ $class = ref($class) || $class;
+ bless $self, $class;
+}
+
+=head2 $t->read
+
+Reads the table into memory
+
+=cut
+
+sub read
+{
+ my ($self, $fh) = @_;
+
+ my $dat;
+ $fh->read($dat, 8);
+ my ($nPairs, $searchRange, $entrySelector, $rangeShift) = unpack("nnnn", $dat);
+
+ my $pairs = [];
+ foreach (1 .. $nPairs) {
+ $fh->read($dat, 6);
+ my ($left, $right, $kern) = TTF_Unpack("SSs", $dat);
+ push @$pairs, { 'left' => $left, 'right' => $right, 'kern' => $kern } if $kern != 0;
+ }
+
+ $self->{'kernPairs'} = $pairs;
+
+ $self;
+}
+
+=head2 $t->out_sub($fh)
+
+Writes the table to a file
+
+=cut
+
+sub out_sub
+{
+ my ($self, $fh) = @_;
+
+ my $pairs = $self->{'kernPairs'};
+ $fh->print(pack("nnnn", TTF_bininfo(scalar @$pairs, 6)));
+
+ foreach (sort { $a->{'left'} <=> $b->{'left'} or $a->{'right'} <=> $b->{'right'} } @$pairs) {
+ $fh->print(TTF_Pack("SSs", $_->{'left'}, $_->{'right'}, $_->{'kern'}));
+ }
+}
+
+=head2 $t->print($fh)
+
+Prints a human-readable representation of the table
+
+=cut
+
+sub dumpXML
+{
+ my ($self, $fh) = @_;
+
+ my $postVal = $self->post()->{'VAL'};
+
+ $fh = 'STDOUT' unless defined $fh;
+ foreach (@{$self->{'kernPairs'}}) {
+ $fh->printf("<pair l=\"%s\" r=\"%s\" v=\"%s\"/>\n", $postVal->[$_->{'left'}], $postVal->[$_->{'right'}], $_->{'kern'});
+ }
+}
+
+
+sub type
+{
+ return 'kernOrderedList';
+}
+
+
+1;
+
+=head1 BUGS
+
+None known
+
+=head1 AUTHOR
+
+Jonathan Kew L<Jonathan_Kew at sil.org>. See L<Font::TTF::Font> for copyright and
+licensing.
+
+=cut
+
Modified: packages/libfont-ttf-perl/trunk/lib/Font/TTF/Kern/StateTable.pm
===================================================================
--- packages/libfont-ttf-perl/trunk/lib/Font/TTF/Kern/StateTable.pm 2006-01-17 02:56:43 UTC (rev 1966)
+++ packages/libfont-ttf-perl/trunk/lib/Font/TTF/Kern/StateTable.pm 2006-01-17 03:07:20 UTC (rev 1967)
@@ -1,142 +1,143 @@
-package Font::TTF::Kern::StateTable;
-
-=head1 NAME
-
-Font::TTF::Kern::StateTable
-
-=head1 METHODS
-
-=cut
-
-use strict;
-use vars qw(@ISA);
-use Font::TTF::Utils;
-use Font::TTF::AATutils;
-use Font::TTF::Kern::Subtable;
-
- at ISA = qw(Font::TTF::Kern::Subtable);
-
-sub new
-{
- my ($class) = @_;
- my ($self) = {};
-
- $class = ref($class) || $class;
- bless $self, $class;
-}
-
-=head2 $t->read
-
-Reads the table into memory
-
-=cut
-
-sub read
-{
- my ($self, $fh) = @_;
- my ($dat);
-
- my $stTableStart = $fh->tell();
-
- my ($classes, $states, $entries) = AAT_read_state_table($fh, 0);
-
- foreach (@$entries) {
- my $flags = $_->{'flags'};
- delete $_->{'flags'};
- $_->{'push'} = 1 if $flags & 0x8000;
- $_->{'noAdvance'} = 1 if $flags & 0x4000;
- $flags &= ~0xC000;
- if ($flags != 0) {
- my $kernList = [];
- $fh->seek($stTableStart + $flags, IO::File::SEEK_SET);
- while (1) {
- $fh->read($dat, 2);
- my $k = TTF_Unpack("s", $dat);
- push @$kernList, ($k & ~1);
- last if ($k & 1) != 0;
- }
- $_->{'kernList'} = $kernList;
- }
- }
-
- $self->{'classes'} = $classes;
- $self->{'states'} = $states;
- $self->{'entries'} = $entries;
-
- $fh->seek($stTableStart - 8 + $self->{'length'}, IO::File::SEEK_SET);
-
- $self;
-}
-
-=head2 $t->out_sub($fh)
-
-Writes the table to a file
-
-=cut
-
-sub out_sub
-{
-}
-
-=head2 $t->print($fh)
-
-Prints a human-readable representation of the table
-
-=cut
-
-sub print
-{
-}
-
-sub dumpXML
-{
- my ($self, $fh) = @_;
-
- $fh->printf("<classes>\n");
- $self->dumpClasses($self->{'classes'}, $fh);
- $fh->printf("</classes>\n");
-
- $fh->printf("<states>\n");
- my $states = $self->{'states'};
- foreach (0 .. $#$states) {
- $fh->printf("<state index=\"%s\">\n", $_);
- my $members = $states->[$_];
- foreach (0 .. $#$members) {
- my $m = $members->[$_];
- $fh->printf("<m index=\"%s\" nextState=\"%s\"", $_, $m->{'nextState'});
- $fh->printf(" push=\"1\"") if $m->{'push'};
- $fh->printf(" noAdvance=\"1\"") if $m->{'noAdvance'};
- if (exists $m->{'kernList'}) {
- $fh->printf(">");
- foreach (@{$m->{'kernList'}}) {
- $fh->printf("<kern v=\"%s\"/>", $_);
- }
- $fh->printf("</m>\n");
- }
- else {
- $fh->printf("/>\n");
- }
- }
- $fh->printf("</state>\n");
- }
- $fh->printf("</states>\n");
-}
-
-sub type
-{
- return 'kernStateTable';
-}
-
-1;
-
-=head1 BUGS
-
-None known
-
-=head1 AUTHOR
-
-Jonathan Kew L<Jonathan_Kew at sil.org>. See L<Font::TTF::Font> for copyright and
-licensing.
-
-=cut
-
+package Font::TTF::Kern::StateTable;
+
+=head1 NAME
+
+Font::TTF::Kern::StateTable
+
+=head1 METHODS
+
+=cut
+
+use strict;
+use vars qw(@ISA);
+use Font::TTF::Utils;
+use Font::TTF::AATutils;
+use Font::TTF::Kern::Subtable;
+use IO::File;
+
+ at ISA = qw(Font::TTF::Kern::Subtable);
+
+sub new
+{
+ my ($class) = @_;
+ my ($self) = {};
+
+ $class = ref($class) || $class;
+ bless $self, $class;
+}
+
+=head2 $t->read
+
+Reads the table into memory
+
+=cut
+
+sub read
+{
+ my ($self, $fh) = @_;
+ my ($dat);
+
+ my $stTableStart = $fh->tell();
+
+ my ($classes, $states, $entries) = AAT_read_state_table($fh, 0);
+
+ foreach (@$entries) {
+ my $flags = $_->{'flags'};
+ delete $_->{'flags'};
+ $_->{'push'} = 1 if $flags & 0x8000;
+ $_->{'noAdvance'} = 1 if $flags & 0x4000;
+ $flags &= ~0xC000;
+ if ($flags != 0) {
+ my $kernList = [];
+ $fh->seek($stTableStart + $flags, IO::File::SEEK_SET);
+ while (1) {
+ $fh->read($dat, 2);
+ my $k = TTF_Unpack("s", $dat);
+ push @$kernList, ($k & ~1);
+ last if ($k & 1) != 0;
+ }
+ $_->{'kernList'} = $kernList;
+ }
+ }
+
+ $self->{'classes'} = $classes;
+ $self->{'states'} = $states;
+ $self->{'entries'} = $entries;
+
+ $fh->seek($stTableStart - 8 + $self->{'length'}, IO::File::SEEK_SET);
+
+ $self;
+}
+
+=head2 $t->out_sub($fh)
+
+Writes the table to a file
+
+=cut
+
+sub out_sub
+{
+}
+
+=head2 $t->print($fh)
+
+Prints a human-readable representation of the table
+
+=cut
+
+sub print
+{
+}
+
+sub dumpXML
+{
+ my ($self, $fh) = @_;
+
+ $fh->printf("<classes>\n");
+ $self->dumpClasses($self->{'classes'}, $fh);
+ $fh->printf("</classes>\n");
+
+ $fh->printf("<states>\n");
+ my $states = $self->{'states'};
+ foreach (0 .. $#$states) {
+ $fh->printf("<state index=\"%s\">\n", $_);
+ my $members = $states->[$_];
+ foreach (0 .. $#$members) {
+ my $m = $members->[$_];
+ $fh->printf("<m index=\"%s\" nextState=\"%s\"", $_, $m->{'nextState'});
+ $fh->printf(" push=\"1\"") if $m->{'push'};
+ $fh->printf(" noAdvance=\"1\"") if $m->{'noAdvance'};
+ if (exists $m->{'kernList'}) {
+ $fh->printf(">");
+ foreach (@{$m->{'kernList'}}) {
+ $fh->printf("<kern v=\"%s\"/>", $_);
+ }
+ $fh->printf("</m>\n");
+ }
+ else {
+ $fh->printf("/>\n");
+ }
+ }
+ $fh->printf("</state>\n");
+ }
+ $fh->printf("</states>\n");
+}
+
+sub type
+{
+ return 'kernStateTable';
+}
+
+1;
+
+=head1 BUGS
+
+None known
+
+=head1 AUTHOR
+
+Jonathan Kew L<Jonathan_Kew at sil.org>. See L<Font::TTF::Font> for copyright and
+licensing.
+
+=cut
+
Modified: packages/libfont-ttf-perl/trunk/lib/Font/TTF/Kern/Subtable.pm
===================================================================
--- packages/libfont-ttf-perl/trunk/lib/Font/TTF/Kern/Subtable.pm 2006-01-17 02:56:43 UTC (rev 1966)
+++ packages/libfont-ttf-perl/trunk/lib/Font/TTF/Kern/Subtable.pm 2006-01-17 03:07:20 UTC (rev 1967)
@@ -1,174 +1,175 @@
-package Font::TTF::Kern::Subtable;
-
-=head1 NAME
-
-Font::TTF::Kern::Subtable
-
-=head1 METHODS
-
-=cut
-
-use strict;
-use Font::TTF::Utils;
-use Font::TTF::AATutils;
-
-require Font::TTF::Kern::OrderedList;
-require Font::TTF::Kern::StateTable;
-require Font::TTF::Kern::ClassArray;
-require Font::TTF::Kern::CompactClassArray;
-
-sub new
-{
- my ($class) = @_;
- my ($self) = {};
-
- $class = ref($class) || $class;
-
- bless $self, $class;
-}
-
-sub create
-{
- my ($class, $type, $coverage, $length) = @_;
-
- $class = ref($class) || $class;
-
- my $subclass;
- if ($type == 0) {
- $subclass = 'Font::TTF::Kern::OrderedList';
- }
- elsif ($type == 1) {
- $subclass = 'Font::TTF::Kern::StateTable';
- }
- elsif ($type == 2) {
- $subclass = 'Font::TTF::Kern::ClassArray';
- }
- elsif ($type == 3) {
- $subclass = 'Font::TTF::Kern::CompactClassArray';
- }
-
- my @options;
- push @options,'vertical' if ($coverage & 0x8000) != 0;
- push @options,'crossStream' if ($coverage & 0x4000) != 0;
- push @options,'variation' if ($coverage & 0x2000) != 0;
-
- my ($subTable) = $subclass->new(@options);
-
- map { $subTable->{$_} = 1 } @options;
-
- $subTable->{'type'} = $type;
- $subTable->{'length'} = $length;
-
- $subTable;
-}
-
-=head2 $t->out($fh)
-
-Writes the table to a file
-
-=cut
-
-sub out
-{
- my ($self, $fh) = @_;
-
- my $subtableStart = $fh->tell();
- my $type = $self->{'type'};
- my $coverage = $type;
- $coverage += 0x4000 if $self->{'direction'} eq 'RL';
- $coverage += 0x2000 if $self->{'orientation'} eq 'VH';
- $coverage += 0x8000 if $self->{'orientation'} eq 'V';
-
- $fh->print(TTF_Pack("SSL", 0, $coverage, $self->{'subFeatureFlags'})); # placeholder for length
-
- $self->out_sub($fh);
-
- my $length = $fh->tell() - $subtableStart;
- my $padBytes = (4 - ($length & 3)) & 3;
- $fh->print(pack("C*", (0) x $padBytes));
- $length += $padBytes;
- $fh->seek($subtableStart, IO::File::SEEK_SET);
- $fh->print(pack("n", $length));
- $fh->seek($subtableStart + $length, IO::File::SEEK_SET);
-}
-
-=head2 $t->print($fh)
-
-Prints a human-readable representation of the table
-
-=cut
-
-sub post
-{
- my ($self) = @_;
-
- my $post = $self->{' PARENT'}{' PARENT'}{'post'};
- if (defined $post) {
- $post->read;
- }
- else {
- $post = {};
- }
-
- return $post;
-}
-
-sub print
-{
- my ($self, $fh) = @_;
-
- my $post = $self->post();
- $fh = 'STDOUT' unless defined $fh;
-}
-
-=head2 $t->print_classes($fh)
-
-Prints a human-readable representation of the table
-
-=cut
-
-sub print_classes
-{
- my ($self, $fh) = @_;
-
- my $post = $self->post();
-
- my $classes = $self->{'classes'};
- foreach (0 .. $#$classes) {
- my $class = $classes->[$_];
- if (defined $class) {
- $fh->printf("\t\tClass %d:\t%s\n", $_, join(", ", map { $_ . " [" . $post->{'VAL'}[$_] . "]" } @$class));
- }
- }
-}
-
-sub dumpClasses
-{
- my ($self, $classes, $fh) = @_;
- my $post = $self->post();
-
- foreach (0 .. $#$classes) {
- my $c = $classes->[$_];
- if ($#$c > -1) {
- $fh->printf("<class n=\"%s\">\n", $_);
- foreach (@$c) {
- $fh->printf("<g index=\"%s\" name=\"%s\"/>\n", $_, $post->{'VAL'}[$_]);
- }
- $fh->printf("</class>\n");
- }
- }
-}
-
-1;
-
-=head1 BUGS
-
-None known
-
-=head1 AUTHOR
-
-Jonathan Kew L<Jonathan_Kew at sil.org>. See L<Font::TTF::Font> for copyright and
-licensing.
-
-=cut
-
+package Font::TTF::Kern::Subtable;
+
+=head1 NAME
+
+Font::TTF::Kern::Subtable
+
+=head1 METHODS
+
+=cut
+
+use strict;
+use Font::TTF::Utils;
+use Font::TTF::AATutils;
+use IO::File;
+
+require Font::TTF::Kern::OrderedList;
+require Font::TTF::Kern::StateTable;
+require Font::TTF::Kern::ClassArray;
+require Font::TTF::Kern::CompactClassArray;
+
+sub new
+{
+ my ($class) = @_;
+ my ($self) = {};
+
+ $class = ref($class) || $class;
+
+ bless $self, $class;
+}
+
+sub create
+{
+ my ($class, $type, $coverage, $length) = @_;
+
+ $class = ref($class) || $class;
+
+ my $subclass;
+ if ($type == 0) {
+ $subclass = 'Font::TTF::Kern::OrderedList';
+ }
+ elsif ($type == 1) {
+ $subclass = 'Font::TTF::Kern::StateTable';
+ }
+ elsif ($type == 2) {
+ $subclass = 'Font::TTF::Kern::ClassArray';
+ }
+ elsif ($type == 3) {
+ $subclass = 'Font::TTF::Kern::CompactClassArray';
+ }
+
+ my @options;
+ push @options,'vertical' if ($coverage & 0x8000) != 0;
+ push @options,'crossStream' if ($coverage & 0x4000) != 0;
+ push @options,'variation' if ($coverage & 0x2000) != 0;
+
+ my ($subTable) = $subclass->new(@options);
+
+ map { $subTable->{$_} = 1 } @options;
+
+ $subTable->{'type'} = $type;
+ $subTable->{'length'} = $length;
+
+ $subTable;
+}
+
+=head2 $t->out($fh)
+
+Writes the table to a file
+
+=cut
+
+sub out
+{
+ my ($self, $fh) = @_;
+
+ my $subtableStart = $fh->tell();
+ my $type = $self->{'type'};
+ my $coverage = $type;
+ $coverage += 0x4000 if $self->{'direction'} eq 'RL';
+ $coverage += 0x2000 if $self->{'orientation'} eq 'VH';
+ $coverage += 0x8000 if $self->{'orientation'} eq 'V';
+
+ $fh->print(TTF_Pack("SSL", 0, $coverage, $self->{'subFeatureFlags'})); # placeholder for length
+
+ $self->out_sub($fh);
+
+ my $length = $fh->tell() - $subtableStart;
+ my $padBytes = (4 - ($length & 3)) & 3;
+ $fh->print(pack("C*", (0) x $padBytes));
+ $length += $padBytes;
+ $fh->seek($subtableStart, IO::File::SEEK_SET);
+ $fh->print(pack("n", $length));
+ $fh->seek($subtableStart + $length, IO::File::SEEK_SET);
+}
+
+=head2 $t->print($fh)
+
+Prints a human-readable representation of the table
+
+=cut
+
+sub post
+{
+ my ($self) = @_;
+
+ my $post = $self->{' PARENT'}{' PARENT'}{'post'};
+ if (defined $post) {
+ $post->read;
+ }
+ else {
+ $post = {};
+ }
+
+ return $post;
+}
+
+sub print
+{
+ my ($self, $fh) = @_;
+
+ my $post = $self->post();
+ $fh = 'STDOUT' unless defined $fh;
+}
+
+=head2 $t->print_classes($fh)
+
+Prints a human-readable representation of the table
+
+=cut
+
+sub print_classes
+{
+ my ($self, $fh) = @_;
+
+ my $post = $self->post();
+
+ my $classes = $self->{'classes'};
+ foreach (0 .. $#$classes) {
+ my $class = $classes->[$_];
+ if (defined $class) {
+ $fh->printf("\t\tClass %d:\t%s\n", $_, join(", ", map { $_ . " [" . $post->{'VAL'}[$_] . "]" } @$class));
+ }
+ }
+}
+
+sub dumpClasses
+{
+ my ($self, $classes, $fh) = @_;
+ my $post = $self->post();
+
+ foreach (0 .. $#$classes) {
+ my $c = $classes->[$_];
+ if ($#$c > -1) {
+ $fh->printf("<class n=\"%s\">\n", $_);
+ foreach (@$c) {
+ $fh->printf("<g index=\"%s\" name=\"%s\"/>\n", $_, $post->{'VAL'}[$_]);
+ }
+ $fh->printf("</class>\n");
+ }
+ }
+}
+
+1;
+
+=head1 BUGS
+
+None known
+
+=head1 AUTHOR
+
+Jonathan Kew L<Jonathan_Kew at sil.org>. See L<Font::TTF::Font> for copyright and
+licensing.
+
+=cut
+
Modified: packages/libfont-ttf-perl/trunk/lib/Font/TTF/Kern.pm
===================================================================
--- packages/libfont-ttf-perl/trunk/lib/Font/TTF/Kern.pm 2006-01-17 02:56:43 UTC (rev 1966)
+++ packages/libfont-ttf-perl/trunk/lib/Font/TTF/Kern.pm 2006-01-17 03:07:20 UTC (rev 1967)
@@ -1,293 +1,293 @@
-package Font::TTF::Kern;
-
-=head1 NAME
-
-Font::TTF::Kern - Kerning tables
-
-=head1 DESCRIPTION
-
-Kerning tables are held as an ordered collection of subtables each giving
-incremental information regarding the kerning of various pairs of glyphs.
-
-The basic structure of the kerning data structure is:
-
- $kern = $f->{'kern'}{'tables'}[$tnum]{'kerns'}{$leftnum}{$rightnum};
-
-Due to the possible complexity of some kerning tables the above information
-is insufficient. Reference also needs to be made to the type of the table and
-the coverage field.
-
-=head1 INSTANCE VARIABLES
-
-The instance variables for a kerning table are relatively straightforward.
-
-=over 4
-
-=item Version
-
-Version number of the kerning table
-
-=item Num
-
-Number of subtables in the kerning table
-
-=item tables
-
-Array of subtables in the kerning table
-
-=over 4
-
-Each subtable has a number of instance variables.
-
-=item kern
-
-A two level hash array containing kerning values. The indexing is left
-value and then right value. In the case of type 2 tables, the indexing
-is via left class and right class. It may seem using hashes is strange,
-but most tables are not type 2 and this method saves empty array values.
-
-=item type
-
-Stores the table type. Only type 0 and type 2 tables are specified for
-TrueType so far.
-
-=item coverage
-
-A bit field of coverage information regarding the kerning value. See the
-TrueType specification for details.
-
-=item Version
-
-Contains the version number of the table.
-
-=item Num
-
-Number of kerning pairs in this type 0 table.
-
-=item left
-
-An array indexed by glyph - left_first which returns a class number for
-the glyph in type 2 tables.
-
-=item right
-
-An array indexed by glyph - right_first which returns a class number for
-the glyph in type 2 tables.
-
-=item left_first
-
-the glyph number of the first element in the left array for type 2 tables.
-
-=item right_first
-
-the glyph number of the first element in the right array for type 2 tables.
-
-=item num_left
-
-Number of left classes
-
-=item num_right
-
-Number of right classes
-
-=back
-
-=back
-
-=head1 METHODS
-
-=cut
-
-use strict;
-use vars qw(@ISA);
-use Font::TTF::Utils;
-use Font::TTF::Table;
-
- at ISA = qw(Font::TTF::Table);
-
-=head2 $t->read
-
-Reads the whole kerning table into structures
-
-=cut
-
-sub read
-{
- my ($self) = @_;
- my ($fh) = $self->{' INFILE'};
- my ($dat, $i, $numt, $len, $cov, $t);
-
- $self->SUPER::read or return $self;
-
- $fh->read($dat, 4);
- ($self->{'Version'}, $numt) = unpack("n2", $dat);
- $self->{'Num'} = $numt;
-
- for ($i = 0; $i < $numt; $i++)
- {
- $t = {};
- $fh->read($dat, 6);
- ($t->{'Version'}, $len, $cov) = unpack("n3", $dat);
- $t->{'coverage'} = $cov & 255;
- $t->{'type'} = $cov >> 8;
- $fh->read($dat, $len - 6);
- if ($t->{'Version'} == 0)
- {
- my ($j);
-
- $t->{'Num'} = unpack("n", $dat);
- for ($j = 0; $j < $t->{'Num'}; $j++)
- {
- my ($f, $l, $v) = TTF_Unpack("SSs", substr($dat, $j * 6 + 8, 6));
- $t->{'kern'}{$f}{$l} = $v;
- }
- } elsif ($t->{'Version'} == 2)
- {
- my ($wid, $off, $numg, $maxl, $maxr, $j);
-
- $wid = unpack("n", $dat);
- $off = unpack("n", substr($dat, 2));
- ($t->{'left_first'}, $numg) = unpack("n2", substr($dat, $off));
- $t->{'left'} = [unpack("C$numg", substr($dat, $off + 4))];
- foreach (@{$t->{'left'}})
- {
- $_ /= $wid;
- $maxl = $_ if ($_ > $maxl);
- }
- $t->{'left_max'} = $maxl;
-
- $off = unpack("n", substr($dat, 4));
- ($t->{'right_first'}, $numg) = unpack("n2", substr($dat, $off));
- $t->{'right'} = [unpack("C$numg", substr($dat, $off + 4))];
- foreach (@{$t->{'right'}})
- {
- $_ >>= 1;
- $maxr = $_ if ($_ > $maxr);
- }
- $t->{'right_max'} = $maxr;
-
- $off = unpack("n", substr($dat, 6));
- for ($j = 0; $j <= $maxl; $j++)
- {
- my ($k) = 0;
-
- map { $t->{'kern'}{$j}{$k} = $_ if $_; $k++; }
- unpack("n$maxr", substr($dat, $off + $wid * $j));
- }
- }
- push (@{$self->{'tables'}}, $t);
- }
- $self;
-}
-
-
-=head2 $t->out($fh)
-
-Outputs the kerning tables to the given file
-
-=cut
-
-sub out
-{
- my ($self, $fh) = @_;
- my ($i, $l, $r, $loc, $loc1, $t);
-
- return $self->SUPER::out($fh) unless ($self->{' read'});
-
- $fh->print(pack("n2", $self->{'Version'}, $self->{'Num'}));
- for ($i = 0; $i < $self->{'Num'}; $i++)
- {
- $t = $self->{'tables'}[$i];
- $loc = $fh->tell();
-
- $fh->print(pack("nnn", $t->{'Version'}, 0, $t->{'coverage'}));
- if ($t->{'Version'} == 0)
- {
- my ($dat);
- foreach $l (sort {$a <=> $b} keys %{$t->{'kern'}})
- {
- foreach $r (sort {$a <=> $b} keys %{$t->{'kern'}{$l}})
- { $dat .= TTF_Pack("SSs", $l, $r, $t->{'kern'}{$l}{$r}); }
- }
- $fh->print(TTF_Pack("SSSS", Font::TTF::Utils::TTF_bininfo(length($dat) / 6, 6)));
- $fh->print($dat);
- } elsif ($t->{'Version'} == 2)
- {
- my ($arr);
-
- $fh->print(pack("nnnn", $t->{'right_max'} << 1, 8, ($#{$t->{'left'}} + 7) << 1,
- ($#{$t->{'left'}} + $#{$t->{'right'}} + 10) << 1));
-
- $fh->print(pack("nn", $t->{'left_first'}, $#{$t->{'left'}} + 1));
- foreach (@{$t->{'left'}})
- { $fh->print(pack("C", $_ * (($t->{'left_max'} + 1) << 1))); }
-
- $fh->print(pack("nn", $t->{'right_first'}, $#{$t->{'right'}} + 1));
- foreach (@{$t->{'right'}})
- { $fh->print(pack("C", $_ << 1)); }
-
- $arr = "\000\000" x (($t->{'left_max'} + 1) * ($t->{'right_max'} + 1));
- foreach $l (keys %{$t->{'kern'}})
- {
- foreach $r (keys %{$t->{'kern'}{$l}})
- { substr($arr, ($l * ($t->{'left_max'} + 1) + $r) << 1, 2)
- = pack("n", $t->{'kern'}{$l}{$r}); }
- }
- $fh->print($arr);
- }
- $loc1 = $fh->tell();
- $fh->seek($loc + 2, 0);
- $fh->print(pack("n", $loc1 - $loc));
- $fh->seek($loc1, 0);
- }
- $self;
-}
-
-
-=head2 $t->XML_element($context, $depth, $key, $value)
-
-Handles outputting the kern hash into XML a little more tidily
-
-=cut
-
-sub XML_element
-{
- my ($self) = shift;
- my ($context, $depth, $key, $value) = @_;
- my ($fh) = $context->{'fh'};
- my ($f, $l);
-
- return $self->SUPER::XML_element(@_) unless ($key eq 'kern');
- $fh->print("$depth<kern-table>\n");
- foreach $f (sort {$a <=> $b} keys %{$value})
- {
- foreach $l (sort {$a <=> $b} keys %{$value->{$f}})
- { $fh->print("$depth$context->{'indent'}<adjust first='$f' last='$l' dist='$value->{$f}{$l}'/>\n"); }
- }
- $fh->print("$depth</kern-table>\n");
- $self;
-}
-
-1;
-
-=head1 BUGS
-
-=over 4
-
-=item *
-
-Only supports kerning table types 0 & 2.
-
-=item *
-
-No real support functions to I<do> anything with the kerning tables yet.
-
-=back
-
-=head1 AUTHOR
-
-Martin Hosken Martin_Hosken at sil.org. See L<Font::TTF::Font> for copyright and
-licensing.
-
-=cut
-
+package Font::TTF::Kern;
+
+=head1 NAME
+
+Font::TTF::Kern - Kerning tables
+
+=head1 DESCRIPTION
+
+Kerning tables are held as an ordered collection of subtables each giving
+incremental information regarding the kerning of various pairs of glyphs.
+
+The basic structure of the kerning data structure is:
+
+ $kern = $f->{'kern'}{'tables'}[$tnum]{'kerns'}{$leftnum}{$rightnum};
+
+Due to the possible complexity of some kerning tables the above information
+is insufficient. Reference also needs to be made to the type of the table and
+the coverage field.
+
+=head1 INSTANCE VARIABLES
+
+The instance variables for a kerning table are relatively straightforward.
+
+=over 4
+
+=item Version
+
+Version number of the kerning table
+
+=item Num
+
+Number of subtables in the kerning table
+
+=item tables
+
+Array of subtables in the kerning table
+
+=over 4
+
+Each subtable has a number of instance variables.
+
+=item kern
+
+A two level hash array containing kerning values. The indexing is left
+value and then right value. In the case of type 2 tables, the indexing
+is via left class and right class. It may seem using hashes is strange,
+but most tables are not type 2 and this method saves empty array values.
+
+=item type
+
+Stores the table type. Only type 0 and type 2 tables are specified for
+TrueType so far.
+
+=item coverage
+
+A bit field of coverage information regarding the kerning value. See the
+TrueType specification for details.
+
+=item Version
+
+Contains the version number of the table.
+
+=item Num
+
+Number of kerning pairs in this type 0 table.
+
+=item left
+
+An array indexed by glyph - left_first which returns a class number for
+the glyph in type 2 tables.
+
+=item right
+
+An array indexed by glyph - right_first which returns a class number for
+the glyph in type 2 tables.
+
+=item left_first
+
+the glyph number of the first element in the left array for type 2 tables.
+
+=item right_first
+
+the glyph number of the first element in the right array for type 2 tables.
+
+=item num_left
+
+Number of left classes
+
+=item num_right
+
+Number of right classes
+
+=back
+
+=back
+
+=head1 METHODS
+
+=cut
+
+use strict;
+use vars qw(@ISA);
+use Font::TTF::Utils;
+use Font::TTF::Table;
+
+ at ISA = qw(Font::TTF::Table);
+
+=head2 $t->read
+
+Reads the whole kerning table into structures
+
+=cut
+
+sub read
+{
+ my ($self) = @_;
+ my ($fh) = $self->{' INFILE'};
+ my ($dat, $i, $numt, $len, $cov, $t);
+
+ $self->SUPER::read or return $self;
+
+ $fh->read($dat, 4);
+ ($self->{'Version'}, $numt) = unpack("n2", $dat);
+ $self->{'Num'} = $numt;
+
+ for ($i = 0; $i < $numt; $i++)
+ {
+ $t = {};
+ $fh->read($dat, 6);
+ ($t->{'Version'}, $len, $cov) = unpack("n3", $dat);
+ $t->{'coverage'} = $cov & 255;
+ $t->{'type'} = $cov >> 8;
+ $fh->read($dat, $len - 6);
+ if ($t->{'Version'} == 0)
+ {
+ my ($j);
+
+ $t->{'Num'} = unpack("n", $dat);
+ for ($j = 0; $j < $t->{'Num'}; $j++)
+ {
+ my ($f, $l, $v) = TTF_Unpack("SSs", substr($dat, $j * 6 + 8, 6));
+ $t->{'kern'}{$f}{$l} = $v;
+ }
+ } elsif ($t->{'Version'} == 2)
+ {
+ my ($wid, $off, $numg, $maxl, $maxr, $j);
+
+ $wid = unpack("n", $dat);
+ $off = unpack("n", substr($dat, 2));
+ ($t->{'left_first'}, $numg) = unpack("n2", substr($dat, $off));
+ $t->{'left'} = [unpack("C$numg", substr($dat, $off + 4))];
+ foreach (@{$t->{'left'}})
+ {
+ $_ /= $wid;
+ $maxl = $_ if ($_ > $maxl);
+ }
+ $t->{'left_max'} = $maxl;
+
+ $off = unpack("n", substr($dat, 4));
+ ($t->{'right_first'}, $numg) = unpack("n2", substr($dat, $off));
+ $t->{'right'} = [unpack("C$numg", substr($dat, $off + 4))];
+ foreach (@{$t->{'right'}})
+ {
+ $_ >>= 1;
+ $maxr = $_ if ($_ > $maxr);
+ }
+ $t->{'right_max'} = $maxr;
+
+ $off = unpack("n", substr($dat, 6));
+ for ($j = 0; $j <= $maxl; $j++)
+ {
+ my ($k) = 0;
+
+ map { $t->{'kern'}{$j}{$k} = $_ if $_; $k++; }
+ unpack("n$maxr", substr($dat, $off + $wid * $j));
+ }
+ }
+ push (@{$self->{'tables'}}, $t);
+ }
+ $self;
+}
+
+
+=head2 $t->out($fh)
+
+Outputs the kerning tables to the given file
+
+=cut
+
+sub out
+{
+ my ($self, $fh) = @_;
+ my ($i, $l, $r, $loc, $loc1, $t);
+
+ return $self->SUPER::out($fh) unless ($self->{' read'});
+
+ $fh->print(pack("n2", $self->{'Version'}, $self->{'Num'}));
+ for ($i = 0; $i < $self->{'Num'}; $i++)
+ {
+ $t = $self->{'tables'}[$i];
+ $loc = $fh->tell();
+
+ $fh->print(pack("nnn", $t->{'Version'}, 0, $t->{'coverage'}));
+ if ($t->{'Version'} == 0)
+ {
+ my ($dat);
+ foreach $l (sort {$a <=> $b} keys %{$t->{'kern'}})
+ {
+ foreach $r (sort {$a <=> $b} keys %{$t->{'kern'}{$l}})
+ { $dat .= TTF_Pack("SSs", $l, $r, $t->{'kern'}{$l}{$r}); }
+ }
+ $fh->print(TTF_Pack("SSSS", Font::TTF::Utils::TTF_bininfo(length($dat) / 6, 6)));
+ $fh->print($dat);
+ } elsif ($t->{'Version'} == 2)
+ {
+ my ($arr);
+
+ $fh->print(pack("nnnn", $t->{'right_max'} << 1, 8, ($#{$t->{'left'}} + 7) << 1,
+ ($#{$t->{'left'}} + $#{$t->{'right'}} + 10) << 1));
+
+ $fh->print(pack("nn", $t->{'left_first'}, $#{$t->{'left'}} + 1));
+ foreach (@{$t->{'left'}})
+ { $fh->print(pack("C", $_ * (($t->{'left_max'} + 1) << 1))); }
+
+ $fh->print(pack("nn", $t->{'right_first'}, $#{$t->{'right'}} + 1));
+ foreach (@{$t->{'right'}})
+ { $fh->print(pack("C", $_ << 1)); }
+
+ $arr = "\000\000" x (($t->{'left_max'} + 1) * ($t->{'right_max'} + 1));
+ foreach $l (keys %{$t->{'kern'}})
+ {
+ foreach $r (keys %{$t->{'kern'}{$l}})
+ { substr($arr, ($l * ($t->{'left_max'} + 1) + $r) << 1, 2)
+ = pack("n", $t->{'kern'}{$l}{$r}); }
+ }
+ $fh->print($arr);
+ }
+ $loc1 = $fh->tell();
+ $fh->seek($loc + 2, 0);
+ $fh->print(pack("n", $loc1 - $loc));
+ $fh->seek($loc1, 0);
+ }
+ $self;
+}
+
+
+=head2 $t->XML_element($context, $depth, $key, $value)
+
+Handles outputting the kern hash into XML a little more tidily
+
+=cut
+
+sub XML_element
+{
+ my ($self) = shift;
+ my ($context, $depth, $key, $value) = @_;
+ my ($fh) = $context->{'fh'};
+ my ($f, $l);
+
+ return $self->SUPER::XML_element(@_) unless ($key eq 'kern');
+ $fh->print("$depth<kern-table>\n");
+ foreach $f (sort {$a <=> $b} keys %{$value})
+ {
+ foreach $l (sort {$a <=> $b} keys %{$value->{$f}})
+ { $fh->print("$depth$context->{'indent'}<adjust first='$f' last='$l' dist='$value->{$f}{$l}'/>\n"); }
+ }
+ $fh->print("$depth</kern-table>\n");
+ $self;
+}
+
+1;
+
+=head1 BUGS
+
+=over 4
+
+=item *
+
+Only supports kerning table types 0 & 2.
+
+=item *
+
+No real support functions to I<do> anything with the kerning tables yet.
+
+=back
+
+=head1 AUTHOR
+
+Martin Hosken Martin_Hosken at sil.org. See L<Font::TTF::Font> for copyright and
+licensing.
+
+=cut
+
Modified: packages/libfont-ttf-perl/trunk/lib/Font/TTF/LTSH.pm
===================================================================
--- packages/libfont-ttf-perl/trunk/lib/Font/TTF/LTSH.pm 2006-01-17 02:56:43 UTC (rev 1966)
+++ packages/libfont-ttf-perl/trunk/lib/Font/TTF/LTSH.pm 2006-01-17 03:07:20 UTC (rev 1967)
@@ -1,88 +1,88 @@
-package Font::TTF::LTSH;
-
-=head1 NAME
-
-Font::TTF::LTSH - Linear Threshold table
-
-=head1 DESCRIPTION
-
-Holds the linear threshold for each glyph. This is the ppem value at which a
-glyph's metrics become linear. The value is set to 1 if a glyph's metrics are
-always linear.
-
-=head1 INSTANCE VARIABLES
-
-=over 4
-
-=item glyphs
-
-An array of ppem values. One value per glyph
-
-=back
-
-=head1 METHODS
-
-=cut
-
-use strict;
-use vars qw(@ISA);
-use Font::TTF::Table;
-
- at ISA = qw(Font::TTF::Table);
-
-=head2 $t->read
-
-Reads the table
-
-=cut
-
-sub read
-{
- my ($self) = @_;
- my ($fh) = $self->{' INFILE'};
- my ($numg, $dat);
-
- $self->SUPER::read or return $self;
-
- $fh->read($dat, 4);
- ($self->{'Version'}, $numg) = unpack("nn", $dat);
- $self->{'Num'} = $numg;
-
- $fh->read($dat, $numg);
- $self->{'glyphs'} = [unpack("C$numg", $dat)];
- $self;
-}
-
-
-=head2 $t->out($fh)
-
-Outputs the LTSH to the given fh.
-
-=cut
-
-sub out
-{
- my ($self, $fh) = @_;
- my ($numg) = $self->{' PARENT'}{'maxp'}{'numGlyphs'};
-
- return $self->SUPER::out($fh) unless ($self->{' read'});
-
- $fh->print(pack("nn", 0, $numg));
- $fh->print(pack("C$numg", @{$self->{'glyphs'}}));
- $self;
-}
-
-
-1;
-
-=head1 BUGS
-
-None known
-
-=head1 AUTHOR
-
-Martin Hosken Martin_Hosken at sil.org. See L<Font::TTF::Font> for copyright and
-licensing.
-
-=cut
-
+package Font::TTF::LTSH;
+
+=head1 NAME
+
+Font::TTF::LTSH - Linear Threshold table
+
+=head1 DESCRIPTION
+
+Holds the linear threshold for each glyph. This is the ppem value at which a
+glyph's metrics become linear. The value is set to 1 if a glyph's metrics are
+always linear.
+
+=head1 INSTANCE VARIABLES
+
+=over 4
+
+=item glyphs
+
+An array of ppem values. One value per glyph
+
+=back
+
+=head1 METHODS
+
+=cut
+
+use strict;
+use vars qw(@ISA);
+use Font::TTF::Table;
+
+ at ISA = qw(Font::TTF::Table);
+
+=head2 $t->read
+
+Reads the table
+
+=cut
+
+sub read
+{
+ my ($self) = @_;
+ my ($fh) = $self->{' INFILE'};
+ my ($numg, $dat);
+
+ $self->SUPER::read or return $self;
+
+ $fh->read($dat, 4);
+ ($self->{'Version'}, $numg) = unpack("nn", $dat);
+ $self->{'Num'} = $numg;
+
+ $fh->read($dat, $numg);
+ $self->{'glyphs'} = [unpack("C$numg", $dat)];
+ $self;
+}
+
+
+=head2 $t->out($fh)
+
+Outputs the LTSH to the given fh.
+
+=cut
+
+sub out
+{
+ my ($self, $fh) = @_;
+ my ($numg) = $self->{' PARENT'}{'maxp'}{'numGlyphs'};
+
+ return $self->SUPER::out($fh) unless ($self->{' read'});
+
+ $fh->print(pack("nn", 0, $numg));
+ $fh->print(pack("C$numg", @{$self->{'glyphs'}}));
+ $self;
+}
+
+
+1;
+
+=head1 BUGS
+
+None known
+
+=head1 AUTHOR
+
+Martin Hosken Martin_Hosken at sil.org. See L<Font::TTF::Font> for copyright and
+licensing.
+
+=cut
+
Modified: packages/libfont-ttf-perl/trunk/lib/Font/TTF/Loca.pm
===================================================================
--- packages/libfont-ttf-perl/trunk/lib/Font/TTF/Loca.pm 2006-01-17 02:56:43 UTC (rev 1966)
+++ packages/libfont-ttf-perl/trunk/lib/Font/TTF/Loca.pm 2006-01-17 03:07:20 UTC (rev 1967)
@@ -1,183 +1,183 @@
-package Font::TTF::Loca;
-
-=head1 NAME
-
-Font::TTF::Loca - the Locations table, which is intimately tied to the glyf table
-
-=head1 DESCRIPTION
-
-The location table holds the directory of locations of each glyph within the
-glyf table. Due to this relationship and the unimportance of the actual locations
-when it comes to holding glyphs in memory, reading the location table results
-in the creation of glyph objects for each glyph and stores them here.
-So if you are looking for glyphs, don't look in the C<glyf> table, look here
-instead.
-
-Things get complicated if you try to change the glyph list within the one table.
-The recommendation is to create another clean location object to replace this
-table in the font, ensuring that the old table is read first and to transfer
-or copy glyphs across from the read table to the new table.
-
-=head1 INSTANCE VARIABLES
-
-The instance variables do not start with a space
-
-=over 4
-
-=item glyphs
-
-An array of glyph objects for each glyph.
-
-=item glyphtype
-
-A string containing the class name to create for each new glyph. If empty,
-defaults to L<Font::TTF::Glyph>.
-
-=back
-
-=head1 METHODS
-
-=cut
-
-use strict;
-use vars qw(@ISA);
- at ISA = qw(Font::TTF::Table);
-
-require Font::TTF::Glyph;
-
-
-=head2 $t->new
-
-Creates a new location table making sure it has a glyphs array
-
-=cut
-
-sub new
-{
- my ($class) = shift;
- my ($res) = $class->SUPER::new(@_);
- $res->{'glyphs'} = [];
- $res;
-}
-
-=head2 $t->read
-
-Reads the location table creating glyph objects (L<Font::TTF::Glyph>) for each glyph
-allowing their later reading.
-
-=cut
-
-sub read
-{
- my ($self) = @_;
- my ($fh) = $self->{' INFILE'};
- my ($locFmt) = $self->{' PARENT'}{'head'}->read->{'indexToLocFormat'};
- my ($numGlyphs) = $self->{' PARENT'}{'maxp'}->read->{'numGlyphs'};
- my ($glyfLoc) = $self->{' PARENT'}{'glyf'}{' OFFSET'};
- my ($dat, $last, $i, $loc);
-
- $self->SUPER::read or return $self;
- $fh->read($dat, $locFmt ? 4 : 2);
- $last = unpack($locFmt ? "N" : "n", $dat);
- for ($i = 0; $i < $numGlyphs; $i++)
- {
- $fh->read($dat, $locFmt ? 4 : 2);
- $loc = unpack($locFmt ? "N" : "n", $dat);
- $self->{'glyphs'}[$i] = ($self->{'glyphtype'} || "Font::TTF::Glyph")->new(
- LOC => $last << ($locFmt ? 0 : 1),
- OUTLOC => $last << ($locFmt ? 0 : 1),
- PARENT => $self->{' PARENT'},
- INFILE => $fh,
- BASE => $glyfLoc,
- OUTLEN => ($loc - $last) << ($locFmt ? 0 : 1),
- LEN => ($loc - $last) << ($locFmt ? 0 : 1)) if ($loc != $last);
- $last = $loc;
- }
- $self;
-}
-
-
-=head2 $t->out($fh)
-
-Writes the location table out to $fh. Notice that not having read the location
-table implies that the glyf table has not been read either, so the numbers in
-the location table are still valid. Let's hope that C<maxp/numGlyphs> and
-C<head/indexToLocFmt> haven't changed otherwise we are in big trouble.
-
-The function uses the OUTLOC location in the glyph calculated when the glyf
-table was attempted to be output.
-
-=cut
-
-sub out
-{
- my ($self, $fh) = @_;
- my ($locFmt) = $self->{' PARENT'}{'head'}->read->{'indexToLocFormat'};
- my ($numGlyphs) = $self->{' PARENT'}{'maxp'}->read->{'numGlyphs'};
- my ($count, $i, $offset, $g);
-
- return $self->SUPER::out($fh) unless ($self->{' read'});
-
- $count = 0;
- for ($i = 0; $i < $numGlyphs; $i++)
- {
- $g = ($self->{'glyphs'}[$i]) || "";
- unless ($g)
- {
- $count++;
- next;
- } else
- {
- if ($locFmt)
- { $fh->print(pack("N", $g->{' OUTLOC'}) x ($count + 1)); }
- else
- { $fh->print(pack("n", $g->{' OUTLOC'} >> 1) x ($count + 1)); }
- $count = 0;
- $offset = $g->{' OUTLOC'} + $g->{' OUTLEN'};
- }
- }
- $fh->print(pack($locFmt ? "N" : "n", ($locFmt ? $offset: $offset >> 1)) x ($count + 1));
-}
-
-
-=head2 $t->out_xml($context, $depth)
-
-No need to output a loca table, this is dynamically generated
-
-=cut
-
-sub out_xml
-{ return $_[0]; }
-
-
-=head2 $t->glyphs_do(&func)
-
-Calls func for each glyph in this location table in numerical order:
-
- &func($glyph, $glyph_num)
-
-=cut
-
-sub glyphs_do
-{
- my ($self, $func) = @_;
- my ($i);
-
- for ($i = 0; $i <= $#{$self->{'glyphs'}}; $i++)
- { &$func($self->{'glyphs'}[$i], $i) if defined $self->{'glyphs'}[$i]; }
- $self;
-}
-
-1;
-
-=head1 BUGS
-
-None known
-
-=head1 AUTHOR
-
-Martin Hosken Martin_Hosken at sil.org. See L<Font::TTF::Font> for copyright and
-licensing.
-
-=cut
-
+package Font::TTF::Loca;
+
+=head1 NAME
+
+Font::TTF::Loca - the Locations table, which is intimately tied to the glyf table
+
+=head1 DESCRIPTION
+
+The location table holds the directory of locations of each glyph within the
+glyf table. Due to this relationship and the unimportance of the actual locations
+when it comes to holding glyphs in memory, reading the location table results
+in the creation of glyph objects for each glyph and stores them here.
+So if you are looking for glyphs, don't look in the C<glyf> table, look here
+instead.
+
+Things get complicated if you try to change the glyph list within the one table.
+The recommendation is to create another clean location object to replace this
+table in the font, ensuring that the old table is read first and to transfer
+or copy glyphs across from the read table to the new table.
+
+=head1 INSTANCE VARIABLES
+
+The instance variables do not start with a space
+
+=over 4
+
+=item glyphs
+
+An array of glyph objects for each glyph.
+
+=item glyphtype
+
+A string containing the class name to create for each new glyph. If empty,
+defaults to L<Font::TTF::Glyph>.
+
+=back
+
+=head1 METHODS
+
+=cut
+
+use strict;
+use vars qw(@ISA);
+ at ISA = qw(Font::TTF::Table);
+
+require Font::TTF::Glyph;
+
+
+=head2 $t->new
+
+Creates a new location table making sure it has a glyphs array
+
+=cut
+
+sub new
+{
+ my ($class) = shift;
+ my ($res) = $class->SUPER::new(@_);
+ $res->{'glyphs'} = [];
+ $res;
+}
+
+=head2 $t->read
+
+Reads the location table creating glyph objects (L<Font::TTF::Glyph>) for each glyph
+allowing their later reading.
+
+=cut
+
+sub read
+{
+ my ($self) = @_;
+ my ($fh) = $self->{' INFILE'};
+ my ($locFmt) = $self->{' PARENT'}{'head'}->read->{'indexToLocFormat'};
+ my ($numGlyphs) = $self->{' PARENT'}{'maxp'}->read->{'numGlyphs'};
+ my ($glyfLoc) = $self->{' PARENT'}{'glyf'}{' OFFSET'};
+ my ($dat, $last, $i, $loc);
+
+ $self->SUPER::read or return $self;
+ $fh->read($dat, $locFmt ? 4 : 2);
+ $last = unpack($locFmt ? "N" : "n", $dat);
+ for ($i = 0; $i < $numGlyphs; $i++)
+ {
+ $fh->read($dat, $locFmt ? 4 : 2);
+ $loc = unpack($locFmt ? "N" : "n", $dat);
+ $self->{'glyphs'}[$i] = ($self->{'glyphtype'} || "Font::TTF::Glyph")->new(
+ LOC => $last << ($locFmt ? 0 : 1),
+ OUTLOC => $last << ($locFmt ? 0 : 1),
+ PARENT => $self->{' PARENT'},
+ INFILE => $fh,
+ BASE => $glyfLoc,
+ OUTLEN => ($loc - $last) << ($locFmt ? 0 : 1),
+ LEN => ($loc - $last) << ($locFmt ? 0 : 1)) if ($loc != $last);
+ $last = $loc;
+ }
+ $self;
+}
+
+
+=head2 $t->out($fh)
+
+Writes the location table out to $fh. Notice that not having read the location
+table implies that the glyf table has not been read either, so the numbers in
+the location table are still valid. Let's hope that C<maxp/numGlyphs> and
+C<head/indexToLocFmt> haven't changed otherwise we are in big trouble.
+
+The function uses the OUTLOC location in the glyph calculated when the glyf
+table was attempted to be output.
+
+=cut
+
+sub out
+{
+ my ($self, $fh) = @_;
+ my ($locFmt) = $self->{' PARENT'}{'head'}->read->{'indexToLocFormat'};
+ my ($numGlyphs) = $self->{' PARENT'}{'maxp'}->read->{'numGlyphs'};
+ my ($count, $i, $offset, $g);
+
+ return $self->SUPER::out($fh) unless ($self->{' read'});
+
+ $count = 0;
+ for ($i = 0; $i < $numGlyphs; $i++)
+ {
+ $g = ($self->{'glyphs'}[$i]) || "";
+ unless ($g)
+ {
+ $count++;
+ next;
+ } else
+ {
+ if ($locFmt)
+ { $fh->print(pack("N", $g->{' OUTLOC'}) x ($count + 1)); }
+ else
+ { $fh->print(pack("n", $g->{' OUTLOC'} >> 1) x ($count + 1)); }
+ $count = 0;
+ $offset = $g->{' OUTLOC'} + $g->{' OUTLEN'};
+ }
+ }
+ $fh->print(pack($locFmt ? "N" : "n", ($locFmt ? $offset: $offset >> 1)) x ($count + 1));
+}
+
+
+=head2 $t->out_xml($context, $depth)
+
+No need to output a loca table, this is dynamically generated
+
+=cut
+
+sub out_xml
+{ return $_[0]; }
+
+
+=head2 $t->glyphs_do(&func)
+
+Calls func for each glyph in this location table in numerical order:
+
+ &func($glyph, $glyph_num)
+
+=cut
+
+sub glyphs_do
+{
+ my ($self, $func) = @_;
+ my ($i);
+
+ for ($i = 0; $i <= $#{$self->{'glyphs'}}; $i++)
+ { &$func($self->{'glyphs'}[$i], $i) if defined $self->{'glyphs'}[$i]; }
+ $self;
+}
+
+1;
+
+=head1 BUGS
+
+None known
+
+=head1 AUTHOR
+
+Martin Hosken Martin_Hosken at sil.org. See L<Font::TTF::Font> for copyright and
+licensing.
+
+=cut
+
Modified: packages/libfont-ttf-perl/trunk/lib/Font/TTF/Manual.pod
===================================================================
--- packages/libfont-ttf-perl/trunk/lib/Font/TTF/Manual.pod 2006-01-17 02:56:43 UTC (rev 1966)
+++ packages/libfont-ttf-perl/trunk/lib/Font/TTF/Manual.pod 2006-01-17 03:07:20 UTC (rev 1967)
@@ -1,214 +1,214 @@
-
-=head1 NAME
-
-Font::TTF::Manual - Information regarding the whole module set
-
-=head1 INTRODUCTION
-
-This document looks at the whole issue of how the various modules in the
-TrueType Font work together. As such it is partly information on this font
-system and partly information on TrueType fonts in general.
-
-Due to the inter-relation between so many tables in a TrueType font, different
-tables will make expectations as to which other tables exist. At the very least
-a font should consist of a C<head> table and a C<maxp> table. The system has
-been designed around the expectation that the necessary tables for font
-rendering in the Windows environment exist. But inter table dependencies have
-been kept to what are considered necessary.
-
-This module set is not meant as a simple to use, mindless, font editing suite,
-but as a low-level, get your hands dirty, know what you are doing, set of
-classes for those who understand the intricacies (and there are many) of
-TrueType fonts. To this end, if you get something wrong in the data structures,
-etc. then this module set won't tell you and will happily create fonts which
-don't work.
-
-At the time of writing, not every TrueType table in existence has been
-implemented! Only the core basic tables of TrueType 1.0 (i.e. no embedded bitmap
-tables, no postscript type tables, no OpenType tables and no GX tables) have
-been implemented. If you want to help by implementing another table or two, then
-please go ahead and send me your code. For a full list of tables, see
-L<Font::TTF::Font>.
-
-
-=head2 Design Principles
-
-PERL is not C++. C++ encourages methods to be written for changing and reading
-each instance variable in a class. If we did this in this PERL program the
-results would be rather large and slow. Instead, since most access will be read
-access, we expose as much of the inner storage of an object to user access
-directly via hash lookup. The advantage this gives are great. For example, by
-following an instance variable chain, looking up the C<yMax> parameter for a
-particular glyph becomes:
-
- $f->{'loca'}{'glyphs'}[$glyph]{'yMax'}
-
-Or, if we are feeling very lazy and don't mind waiting:
-
- $f->{'loca'}{'glyphs'}[$f->{'cmap'}->ms_lookup(0x41)]{'yMax'}
-
-The disadvantage of this method is that it behoves module users to behave
-themselves. Thus it does not hold your hand and ensure that if you make a change
-to a table, that the table is marked as I<dirty>, or that other tables are
-updated accordingly.
-
-It is up to the application developer to understand the implications of the
-changes they make to a font, and to take the necessary action to ensure that the
-data they get out is what they want. Thus, you could go and change the C<yMax>
-value on a glyph and output a new font with this change, but it is up to you to
-ensure that the font's bounding box details in the C<head> table are correct,
-and even that your changing C<yMax> is well motivated.
-
-To help with using the system, each module (or table) will not only describe the
-methods it supports, which are relatively few, but also the instance variables
-it supports, which are many. Most of the variables directly reflect table
-attributes as specified in the OpenType specification, available from Microsoft
-(L<http::/www.microsoft.com/typography>), Adobe and Apple. A list of the names
-used is also given in each module, but not necessarily with any further
-description. After all, this code is not a TrueType manual as well!
-
-
-=head2 Conventions
-
-There are various conventions used in this system.
-
-Firstly we consider the documentation conventions regarding instance variables.
-Each instance variable is marked indicating whether it is a B<(P)>rivate
-variable which users of the module are not expected to read and certainly not
-write to or a B<(R)>ead only variable which users may well want to read but not
-write to.
-
-
-=head1 METHODS
-
-This section examines various methods and how the various modules work with
-these methods.
-
-
-=head2 read and read_dat
-
-Before the data structures for a table can be accessed, they need to be filled
-in from somewhere. The usual way to do this is to read an existing TrueType
-font. This may be achieved by:
-
- $f = Font::TTF::Font->open($filename) || die "Unable to read $filename";
-
-This will open an existing font and read its directory header. Notice that at
-this point, none of the tables in the font have been read. (Actually, the
-C<head> and C<maxp> tables are read at this point too since they contain the
-commonly required parameters of):
-
- $f->{'head'}{'unitsPerEm'}
- $f->{'maxp'}{'numGlyphs'}
-
-In order to be able to access information from a table, it is first necessary to
-C<read> it. Consider trying to find the advance width of a space character
-(U+0020). The following code should do it:
-
- $f = Font::TTF::Font->open($ARGV[0]);
- $snum = $f->{'cmap'}->ms_lookup(0x0020);
- $sadv = $f->{'hmtx'}{'advance'}[$snum];
- print $sadv;
-
-This would result in the value zero being printed, which is far from correct.
-But why? The first line would correctly read the font directory. The second line
-would, incidently, correctly locate the space character in the Windows cmap
-(assuming a non symbol encoded font). The third line would not succeed in its
-task since the C<hmtx> table has not been filled in from the font file. To
-achieve what we want we would first need to cause it to be read:
-
- $f->{'hmtx'}->read;
- $sadv = $f->{'hmtx'}{'advance'}[$snum];
-
-Or for those who are too lazy to write multiple lines, C<read> returns the
-object it reads. Thus we could write:
-
- $sadv = $f->{'hmtx'}->read->{'advance'}[$snum];
-
-Why, if we always have to read tables before accessing information from them,
-did we not have to do this for the C<cmap> table? The answer lies in the method
-call. It senses that the table hasn't been read and reads it for us. This will
-generally happen with all method calls, it is only when we do direct data access
-that we have to take the responsibility to read the table first.
-
-Reading a table does not necessarily result in all the data being placed into
-internal data structures. In the case of a simple table C<read> is sufficient.
-In fact, the normal case is that C<read_dat> reads the data from the file into
-an instance variable called C<' dat'> (including the space) and not into the
-data structures.
-
-This is true except for the C<glyph> class which represents a single glyph. Here
-the process is reversed. Reading a C<glyph> reads the data for the glyph into
-the C<' dat'> instance variable and sets various header attributes for the glyph
-(C<xMin>, C<numContours>, etc.). The data is converted out of the variable into
-data structures via the C<read_dat> method.
-
-The aim, therefore, is that C<read> should do the natural thing (read into data
-structures for those tables and elements for which it is helpful -- all except
-C<glyph> at present) and C<read_dat> should do the unnatural thing: read just
-the binary data for normal tables and convert binary data to data structures for
-C<glyph>s.
-
-In summary, therefore, use C<read> unless you want to hack around with the
-internals of glyphs in which case see L<Font::TTF::Glyph> for more details.
-
-
-=head2 update
-
-The aim of this method is to allow the various data elements in a C<read> font
-to update themselves. All tables know how to update themselves. All tables also
-contain information which cannot be I<updated> but is new knowledge in the font.
-As a result, certain tables do nothing when they are updated. We can, therefore,
-build an update hierarchy of tables, with the independent tables at the bottom
-and C<Font> at the top:
-
- +--loca
- |
- glyf--+--maxp
- |
- +---+--head
- |
- hmtx------+--hhea
-
- cmap-----OS/2
-
- name--
-
- post--
-
-There is an important universal dependency which it is up to the user to
-keep up to date. This is C<maxp/numOfGlyphs> which is used to iterate over all
-the glyphs. Note that the glyphs themselves are not held in the C<glyph> table
-but in the C<loca> table, so adding glyphs, etc. automatically involves keeping
-the C<loca> table up to date.
-
-=head2 Creating fonts
-
-Suppose we were creating a font from scratch. How much information do we need
-to supply and how much will C<update> do for us?
-
-The following information is required:
-
- $f->{'loca'}{'glyphs'}
- $f->{'head'}{'upem'}
- $f->{'maxp'}{'numGlyphs'} (doesn't come from $f->{'loca'}{'glyphs'})
- $f->{'hmtx'}{'advance'}
- $f->{'post'}['format'}
- $f->{'post'}{'VAL'}
- $f->{'cmap'}
- $f->{'name'}
-
-Pretty much everything else is calculated for you. Details of what is needed
-for a glyph may be found in L<Font::TTF::Glyph>. Once we have all the
-information we need (and there is lots more that you could add) then we simply
-
- $f->dirty; # mark all tables dirty
- $f->update; # update the font
-
-=head1 AUTHOR
-
-Martin Hosken Martin_Hosken at sil.org. See L<Font::TTF::Font> for copyright and
-licensing.
-
-=cut
-
+
+=head1 TITLE
+
+Font::TTF::Manual - Information regarding the whole module set
+
+=head1 INTRODUCTION
+
+This document looks at the whole issue of how the various modules in the
+TrueType Font work together. As such it is partly information on this font
+system and partly information on TrueType fonts in general.
+
+Due to the inter-relation between so many tables in a TrueType font, different
+tables will make expectations as to which other tables exist. At the very least
+a font should consist of a C<head> table and a C<maxp> table. The system has
+been designed around the expectation that the necessary tables for font
+rendering in the Windows environment exist. But inter table dependencies have
+been kept to what are considered necessary.
+
+This module set is not meant as a simple to use, mindless, font editing suite,
+but as a low-level, get your hands dirty, know what you are doing, set of
+classes for those who understand the intricacies (and there are many) of
+TrueType fonts. To this end, if you get something wrong in the data structures,
+etc. then this module set won't tell you and will happily create fonts which
+don't work.
+
+At the time of writing, not every TrueType table in existence has been
+implemented! Only the core basic tables of TrueType 1.0 (i.e. no embedded bitmap
+tables, no postscript type tables, no OpenType tables and no GX tables) have
+been implemented. If you want to help by implementing another table or two, then
+please go ahead and send me your code. For a full list of tables, see
+L<Font::TTF::Font>.
+
+
+=head2 Design Principles
+
+PERL is not C++. C++ encourages methods to be written for changing and reading
+each instance variable in a class. If we did this in this PERL program the
+results would be rather large and slow. Instead, since most access will be read
+access, we expose as much of the inner storage of an object to user access
+directly via hash lookup. The advantage this gives are great. For example, by
+following an instance variable chain, looking up the C<yMax> parameter for a
+particular glyph becomes:
+
+ $f->{'loca'}{'glyphs'}[$glyph]{'yMax'}
+
+Or, if we are feeling very lazy and don't mind waiting:
+
+ $f->{'loca'}{'glyphs'}[$f->{'cmap'}->ms_lookup(0x41)]{'yMax'}
+
+The disadvantage of this method is that it behoves module users to behave
+themselves. Thus it does not hold your hand and ensure that if you make a change
+to a table, that the table is marked as I<dirty>, or that other tables are
+updated accordingly.
+
+It is up to the application developer to understand the implications of the
+changes they make to a font, and to take the necessary action to ensure that the
+data they get out is what they want. Thus, you could go and change the C<yMax>
+value on a glyph and output a new font with this change, but it is up to you to
+ensure that the font's bounding box details in the C<head> table are correct,
+and even that your changing C<yMax> is well motivated.
+
+To help with using the system, each module (or table) will not only describe the
+methods it supports, which are relatively few, but also the instance variables
+it supports, which are many. Most of the variables directly reflect table
+attributes as specified in the OpenType specification, available from Microsoft
+(L<http::/www.microsoft.com/typography>), Adobe and Apple. A list of the names
+used is also given in each module, but not necessarily with any further
+description. After all, this code is not a TrueType manual as well!
+
+
+=head2 Conventions
+
+There are various conventions used in this system.
+
+Firstly we consider the documentation conventions regarding instance variables.
+Each instance variable is marked indicating whether it is a B<(P)>rivate
+variable which users of the module are not expected to read and certainly not
+write to or a B<(R)>ead only variable which users may well want to read but not
+write to.
+
+
+=head1 METHODS
+
+This section examines various methods and how the various modules work with
+these methods.
+
+
+=head2 read and read_dat
+
+Before the data structures for a table can be accessed, they need to be filled
+in from somewhere. The usual way to do this is to read an existing TrueType
+font. This may be achieved by:
+
+ $f = Font::TTF::Font->open($filename) || die "Unable to read $filename";
+
+This will open an existing font and read its directory header. Notice that at
+this point, none of the tables in the font have been read. (Actually, the
+C<head> and C<maxp> tables are read at this point too since they contain the
+commonly required parameters of):
+
+ $f->{'head'}{'unitsPerEm'}
+ $f->{'maxp'}{'numGlyphs'}
+
+In order to be able to access information from a table, it is first necessary to
+C<read> it. Consider trying to find the advance width of a space character
+(U+0020). The following code should do it:
+
+ $f = Font::TTF::Font->open($ARGV[0]);
+ $snum = $f->{'cmap'}->ms_lookup(0x0020);
+ $sadv = $f->{'hmtx'}{'advance'}[$snum];
+ print $sadv;
+
+This would result in the value zero being printed, which is far from correct.
+But why? The first line would correctly read the font directory. The second line
+would, incidently, correctly locate the space character in the Windows cmap
+(assuming a non symbol encoded font). The third line would not succeed in its
+task since the C<hmtx> table has not been filled in from the font file. To
+achieve what we want we would first need to cause it to be read:
+
+ $f->{'hmtx'}->read;
+ $sadv = $f->{'hmtx'}{'advance'}[$snum];
+
+Or for those who are too lazy to write multiple lines, C<read> returns the
+object it reads. Thus we could write:
+
+ $sadv = $f->{'hmtx'}->read->{'advance'}[$snum];
+
+Why, if we always have to read tables before accessing information from them,
+did we not have to do this for the C<cmap> table? The answer lies in the method
+call. It senses that the table hasn't been read and reads it for us. This will
+generally happen with all method calls, it is only when we do direct data access
+that we have to take the responsibility to read the table first.
+
+Reading a table does not necessarily result in all the data being placed into
+internal data structures. In the case of a simple table C<read> is sufficient.
+In fact, the normal case is that C<read_dat> reads the data from the file into
+an instance variable called C<' dat'> (including the space) and not into the
+data structures.
+
+This is true except for the C<glyph> class which represents a single glyph. Here
+the process is reversed. Reading a C<glyph> reads the data for the glyph into
+the C<' dat'> instance variable and sets various header attributes for the glyph
+(C<xMin>, C<numContours>, etc.). The data is converted out of the variable into
+data structures via the C<read_dat> method.
+
+The aim, therefore, is that C<read> should do the natural thing (read into data
+structures for those tables and elements for which it is helpful -- all except
+C<glyph> at present) and C<read_dat> should do the unnatural thing: read just
+the binary data for normal tables and convert binary data to data structures for
+C<glyph>s.
+
+In summary, therefore, use C<read> unless you want to hack around with the
+internals of glyphs in which case see L<Font::TTF::Glyph> for more details.
+
+
+=head2 update
+
+The aim of this method is to allow the various data elements in a C<read> font
+to update themselves. All tables know how to update themselves. All tables also
+contain information which cannot be I<updated> but is new knowledge in the font.
+As a result, certain tables do nothing when they are updated. We can, therefore,
+build an update hierarchy of tables, with the independent tables at the bottom
+and C<Font> at the top:
+
+ +--loca
+ |
+ glyf--+--maxp
+ |
+ +---+--head
+ |
+ hmtx------+--hhea
+
+ cmap-----OS/2
+
+ name--
+
+ post--
+
+There is an important universal dependency which it is up to the user to
+keep up to date. This is C<maxp/numOfGlyphs> which is used to iterate over all
+the glyphs. Note that the glyphs themselves are not held in the C<glyph> table
+but in the C<loca> table, so adding glyphs, etc. automatically involves keeping
+the C<loca> table up to date.
+
+=head2 Creating fonts
+
+Suppose we were creating a font from scratch. How much information do we need
+to supply and how much will C<update> do for us?
+
+The following information is required:
+
+ $f->{'loca'}{'glyphs'}
+ $f->{'head'}{'upem'}
+ $f->{'maxp'}{'numGlyphs'} (doesn't come from $f->{'loca'}{'glyphs'})
+ $f->{'hmtx'}{'advance'}
+ $f->{'post'}['format'}
+ $f->{'post'}{'VAL'}
+ $f->{'cmap'}
+ $f->{'name'}
+
+Pretty much everything else is calculated for you. Details of what is needed
+for a glyph may be found in L<Font::TTF::Glyph>. Once we have all the
+information we need (and there is lots more that you could add) then we simply
+
+ $f->dirty; # mark all tables dirty
+ $f->update; # update the font
+
+=head1 AUTHOR
+
+Martin Hosken Martin_Hosken at sil.org. See L<Font::TTF::Font> for copyright and
+licensing.
+
+=cut
+
Modified: packages/libfont-ttf-perl/trunk/lib/Font/TTF/Maxp.pm
===================================================================
--- packages/libfont-ttf-perl/trunk/lib/Font/TTF/Maxp.pm 2006-01-17 02:56:43 UTC (rev 1966)
+++ packages/libfont-ttf-perl/trunk/lib/Font/TTF/Maxp.pm 2006-01-17 03:07:20 UTC (rev 1967)
@@ -1,177 +1,177 @@
-package Font::TTF::Maxp;
-
-=head1 NAME
-
-Font::TTF::Maxp - Maximum Profile table in a font
-
-=head1 DESCRIPTION
-
-A collection of useful instance variables following the TTF standard. Probably
-the most used being C<numGlyphs>. Note that this particular value is
-foundational and should be kept up to date by the application, it is not updated
-by C<update>.
-
-Handles table versions 0.5, 1.0
-
-=head1 INSTANCE VARIABLES
-
-No others beyond those specified in the standard:
-
- numGlyphs
- maxPoints
- maxContours
- maxCompositePoints
- maxCompositeContours
- maxZones
- maxTwilightPoints
- maxStorage
- maxFunctionDefs
- maxInstructionDefs
- maxStackElements
- maxSizeOfInstructions
- maxComponentElements
- maxComponentDepth
-
-
-=head1 METHODS
-
-=cut
-
-use strict;
-use vars qw(@ISA %fields @field_info);
-use Font::TTF::Utils;
-
- at ISA = qw(Font::TTF::Table);
- at field_info = (
- 'numGlyphs' => 'S',
- 'maxPoints' => 'S',
- 'maxContours' => 'S',
- 'maxCompositePoints' => 'S',
- 'maxCompositeContours' => 'S',
- 'maxZones' => 'S',
- 'maxTwilightPoints' => 'S',
- 'maxStorage' => 'S',
- 'maxFunctionDefs' => 'S',
- 'maxInstructionDefs' => 'S',
- 'maxStackElements' => 'S',
- 'maxSizeOfInstructions' => 'S',
- 'maxComponentElements' => 'S',
- 'maxComponentDepth' => 'S');
-
-sub init
-{
- my ($k, $v, $c, $i);
- for ($i = 0; $i < $#field_info; $i += 2)
- {
- ($k, $v, $c) = TTF_Init_Fields($field_info[$i], $c, $field_info[$i + 1]);
- next unless defined $k && $k ne "";
- $fields{$k} = $v;
- }
-}
-
-
-=head2 $t->read
-
-Reads the table into memory
-
-=cut
-
-sub read
-{
- my ($self) = @_;
- my ($dat);
-
- $self->SUPER::read or return $self;
-
- init unless defined $fields{'numGlyphs'}; # any key would do
- $self->{' INFILE'}->read($dat, 4);
- $self->{'version'} = TTF_Unpack("f", $dat);
-
- if ($self->{'version'} == 0.5)
- {
- $self->{' INFILE'}->read($dat, 2);
- $self->{'numGlyphs'} = unpack("n", $dat);
- } else
- {
- $self->{' INFILE'}->read($dat, 28);
- TTF_Read_Fields($self, $dat, \%fields);
- }
- $self;
-}
-
-
-=head2 $t->out($fh)
-
-Writes the table to a file either from memory or by copying.
-
-=cut
-
-sub out
-{
- my ($self, $fh) = @_;
-
- return $self->SUPER::out($fh) unless $self->{' read'};
- $fh->print(TTF_Pack("f", $self->{'version'}));
-
- if ($self->{'version'} == 0.5)
- { $fh->print(pack("n", $self->{'numGlyphs'})); }
- else
- { $fh->print(TTF_Out_Fields($self, \%fields, 28)); }
- $self;
-}
-
-
-=head2 $t->update
-
-Calculates all the maximum values for a font based on the glyphs in the font.
-Only those fields which require hinting code interpretation are ignored and
-left as they were read.
-
-=cut
-
-sub update
-{
- my ($self) = @_;
- my ($i, $num, @n, @m, $j);
- my (@name) = qw(maxPoints maxContours maxCompositePoints maxCompositeContours
- maxSizeOfInstructions maxComponentElements maxComponentDepth);
-
- return undef unless ($self->SUPER::update);
- return undef if ($self->{'version'} == 0.5); # only got numGlyphs
- return undef unless (defined $self->{' PARENT'}{'loca'});
- $self->{' PARENT'}{'loca'}->update;
- $num = $self->{'numGlyphs'};
-
- for ($i = 0; $i < $num; $i++)
- {
- my ($g) = $self->{' PARENT'}{'loca'}{'glyphs'}[$i] || next;
-
- @n = $g->maxInfo($self->{' PARENT'}{'loca'}{'glyphs'});
-
- for ($j = 0; $j <= $#n; $j++)
- { $m[$j] = $n[$j] if $n[$j] > $m[$j]; }
- }
-
- foreach ('prep', 'fpgm')
- { $m[4] = length($self->{' PARENT'}{$_}{' dat'})
- if (defined $self->{' PARENT'}{$_}
- && length($self->{' PARENT'}{$_}{' dat'}) > $m[4]);
- }
-
- for ($j = 0; $j <= $#name; $j++)
- { $self->{$name[$j]} = $m[$j]; }
- $self;
-}
-1;
-
-
-=head1 BUGS
-
-None known
-
-=head1 AUTHOR
-
-Martin Hosken Martin_Hosken at sil.org. See L<Font::TTF::Font> for copyright and
-licensing.
-
-=cut
+package Font::TTF::Maxp;
+
+=head1 NAME
+
+Font::TTF::Maxp - Maximum Profile table in a font
+
+=head1 DESCRIPTION
+
+A collection of useful instance variables following the TTF standard. Probably
+the most used being C<numGlyphs>. Note that this particular value is
+foundational and should be kept up to date by the application, it is not updated
+by C<update>.
+
+Handles table versions 0.5, 1.0
+
+=head1 INSTANCE VARIABLES
+
+No others beyond those specified in the standard:
+
+ numGlyphs
+ maxPoints
+ maxContours
+ maxCompositePoints
+ maxCompositeContours
+ maxZones
+ maxTwilightPoints
+ maxStorage
+ maxFunctionDefs
+ maxInstructionDefs
+ maxStackElements
+ maxSizeOfInstructions
+ maxComponentElements
+ maxComponentDepth
+
+
+=head1 METHODS
+
+=cut
+
+use strict;
+use vars qw(@ISA %fields @field_info);
+use Font::TTF::Utils;
+
+ at ISA = qw(Font::TTF::Table);
+ at field_info = (
+ 'numGlyphs' => 'S',
+ 'maxPoints' => 'S',
+ 'maxContours' => 'S',
+ 'maxCompositePoints' => 'S',
+ 'maxCompositeContours' => 'S',
+ 'maxZones' => 'S',
+ 'maxTwilightPoints' => 'S',
+ 'maxStorage' => 'S',
+ 'maxFunctionDefs' => 'S',
+ 'maxInstructionDefs' => 'S',
+ 'maxStackElements' => 'S',
+ 'maxSizeOfInstructions' => 'S',
+ 'maxComponentElements' => 'S',
+ 'maxComponentDepth' => 'S');
+
+sub init
+{
+ my ($k, $v, $c, $i);
+ for ($i = 0; $i < $#field_info; $i += 2)
+ {
+ ($k, $v, $c) = TTF_Init_Fields($field_info[$i], $c, $field_info[$i + 1]);
+ next unless defined $k && $k ne "";
+ $fields{$k} = $v;
+ }
+}
+
+
+=head2 $t->read
+
+Reads the table into memory
+
+=cut
+
+sub read
+{
+ my ($self) = @_;
+ my ($dat);
+
+ $self->SUPER::read or return $self;
+
+ init unless defined $fields{'numGlyphs'}; # any key would do
+ $self->{' INFILE'}->read($dat, 4);
+ $self->{'version'} = TTF_Unpack("f", $dat);
+
+ if ($self->{'version'} == 0.5)
+ {
+ $self->{' INFILE'}->read($dat, 2);
+ $self->{'numGlyphs'} = unpack("n", $dat);
+ } else
+ {
+ $self->{' INFILE'}->read($dat, 28);
+ TTF_Read_Fields($self, $dat, \%fields);
+ }
+ $self;
+}
+
+
+=head2 $t->out($fh)
+
+Writes the table to a file either from memory or by copying.
+
+=cut
+
+sub out
+{
+ my ($self, $fh) = @_;
+
+ return $self->SUPER::out($fh) unless $self->{' read'};
+ $fh->print(TTF_Pack("f", $self->{'version'}));
+
+ if ($self->{'version'} == 0.5)
+ { $fh->print(pack("n", $self->{'numGlyphs'})); }
+ else
+ { $fh->print(TTF_Out_Fields($self, \%fields, 28)); }
+ $self;
+}
+
+
+=head2 $t->update
+
+Calculates all the maximum values for a font based on the glyphs in the font.
+Only those fields which require hinting code interpretation are ignored and
+left as they were read.
+
+=cut
+
+sub update
+{
+ my ($self) = @_;
+ my ($i, $num, @n, @m, $j);
+ my (@name) = qw(maxPoints maxContours maxCompositePoints maxCompositeContours
+ maxSizeOfInstructions maxComponentElements maxComponentDepth);
+
+ return undef unless ($self->SUPER::update);
+ return undef if ($self->{'version'} == 0.5); # only got numGlyphs
+ return undef unless (defined $self->{' PARENT'}{'loca'});
+ $self->{' PARENT'}{'loca'}->update;
+ $num = $self->{'numGlyphs'};
+
+ for ($i = 0; $i < $num; $i++)
+ {
+ my ($g) = $self->{' PARENT'}{'loca'}{'glyphs'}[$i] || next;
+
+ @n = $g->maxInfo($self->{' PARENT'}{'loca'}{'glyphs'});
+
+ for ($j = 0; $j <= $#n; $j++)
+ { $m[$j] = $n[$j] if $n[$j] > $m[$j]; }
+ }
+
+ foreach ('prep', 'fpgm')
+ { $m[4] = length($self->{' PARENT'}{$_}{' dat'})
+ if (defined $self->{' PARENT'}{$_}
+ && length($self->{' PARENT'}{$_}{' dat'}) > $m[4]);
+ }
+
+ for ($j = 0; $j <= $#name; $j++)
+ { $self->{$name[$j]} = $m[$j]; }
+ $self;
+}
+1;
+
+
+=head1 BUGS
+
+None known
+
+=head1 AUTHOR
+
+Martin Hosken Martin_Hosken at sil.org. See L<Font::TTF::Font> for copyright and
+licensing.
+
+=cut
Modified: packages/libfont-ttf-perl/trunk/lib/Font/TTF/Mort/Chain.pm
===================================================================
--- packages/libfont-ttf-perl/trunk/lib/Font/TTF/Mort/Chain.pm 2006-01-17 02:56:43 UTC (rev 1966)
+++ packages/libfont-ttf-perl/trunk/lib/Font/TTF/Mort/Chain.pm 2006-01-17 03:07:20 UTC (rev 1967)
@@ -1,195 +1,196 @@
-package Font::TTF::Mort::Chain;
-
-=head1 NAME
-
-Font::TTF::Mort::Chain
-
-=cut
-
-use strict;
-use Font::TTF::Utils;
-use Font::TTF::AATutils;
-use Font::TTF::Mort::Subtable;
-
-=head2 $t->new
-
-=cut
-
-sub new
-{
- my ($class, %parms) = @_;
- my ($self) = {};
- my ($p);
-
- $class = ref($class) || $class;
- foreach $p (keys %parms)
- { $self->{" $p"} = $parms{$p}; }
- bless $self, $class;
-}
-
-=head2 $t->read($fh)
-
-Reads the chain into memory
-
-=cut
-
-sub read
-{
- my ($self, $fh) = @_;
- my ($dat);
-
- my $chainStart = $fh->tell();
- $fh->read($dat, 12);
- my ($defaultFlags, $chainLength, $nFeatureEntries, $nSubtables) = TTF_Unpack("LLSS", $dat);
-
- my $featureEntries = [];
- foreach (1 .. $nFeatureEntries) {
- $fh->read($dat, 12);
- my ($featureType, $featureSetting, $enableFlags, $disableFlags) = TTF_Unpack("SSLL", $dat);
- push @$featureEntries, {
- 'type' => $featureType,
- 'setting' => $featureSetting,
- 'enable' => $enableFlags,
- 'disable' => $disableFlags
- };
- }
-
- my $subtables = [];
- foreach (1 .. $nSubtables) {
- my $subtableStart = $fh->tell();
-
- $fh->read($dat, 8);
- my ($length, $coverage, $subFeatureFlags) = TTF_Unpack("SSL", $dat);
- my $type = $coverage & 0x0007;
-
- my $subtable = Font::TTF::Mort::Subtable->create($type, $coverage, $subFeatureFlags, $length);
- $subtable->read($fh);
- $subtable->{' PARENT'} = $self;
-
- push @$subtables, $subtable;
- $fh->seek($subtableStart + $length, IO::File::SEEK_SET);
- }
-
- $self->{'defaultFlags'} = $defaultFlags;
- $self->{'featureEntries'} = $featureEntries;
- $self->{'subtables'} = $subtables;
-
- $fh->seek($chainStart + $chainLength, IO::File::SEEK_SET);
-
- $self;
-}
-
-=head2 $t->out($fh)
-
-Writes the table to a file either from memory or by copying
-
-=cut
-
-sub out
-{
- my ($self, $fh) = @_;
-
- my $chainStart = $fh->tell();
- my ($featureEntries, $subtables) = ($_->{'featureEntries'}, $_->{'subtables'});
- $fh->print(TTF_Pack("LLSS", $_->{'defaultFlags'}, 0, scalar @$featureEntries, scalar @$subtables)); # placeholder for length
-
- foreach (@$featureEntries) {
- $fh->print(TTF_Pack("SSLL", $_->{'type'}, $_->{'setting'}, $_->{'enable'}, $_->{'disable'}));
- }
-
- foreach (@$subtables) {
- $_->out($fh);
- }
-
- my $chainLength = $fh->tell() - $chainStart;
- $fh->seek($chainStart + 4, IO::File::SEEK_SET);
- $fh->print(pack("N", $chainLength));
- $fh->seek($chainStart + $chainLength, IO::File::SEEK_SET);
-}
-
-=head2 $t->print($fh)
-
-Prints a human-readable representation of the chain
-
-=cut
-
-sub feat
-{
- my ($self) = @_;
-
- my $feat = $self->{' PARENT'}{' PARENT'}{'feat'};
- if (defined $feat) {
- $feat->read;
- }
- else {
- $feat = {};
- }
-
- return $feat;
-}
-
-sub print
-{
- my ($self, $fh) = @_;
-
- $fh->printf("version %f\n", $self->{'version'});
-
- my $defaultFlags = $self->{'defaultFlags'};
- $fh->printf("chain: defaultFlags = %08x\n", $defaultFlags);
-
- my $feat = $self->feat();
- my $featureEntries = $self->{'featureEntries'};
- foreach (@$featureEntries) {
- $fh->printf("\tfeature %d, setting %d : enableFlags = %08x, disableFlags = %08x # '%s: %s'\n",
- $_->{'type'}, $_->{'setting'}, $_->{'enable'}, $_->{'disable'},
- $feat->settingName($_->{'type'}, $_->{'setting'}));
- }
-
- my $subtables = $self->{'subtables'};
- foreach (@$subtables) {
- my $type = $_->{'type'};
- my $subFeatureFlags = $_->{'subFeatureFlags'};
- $fh->printf("\n\t%s table, %s, %s, subFeatureFlags = %08x # %s (%s)\n",
- subtable_type_($type), $_->{'direction'}, $_->{'orientation'}, $subFeatureFlags,
- "Default " . ((($subFeatureFlags & $defaultFlags) != 0) ? "On" : "Off"),
- join(", ",
- map {
- join(": ", $feat->settingName($_->{'type'}, $_->{'setting'}) )
- } grep { ($_->{'enable'} & $subFeatureFlags) != 0 } @$featureEntries
- ) );
-
- $_->print($fh);
- }
-}
-
-sub subtable_type_
-{
- my ($val) = @_;
- my ($res);
-
- my @types = (
- 'Rearrangement',
- 'Contextual',
- 'Ligature',
- undef,
- 'Non-contextual',
- 'Insertion',
- );
- $res = $types[$val] or ('Undefined (' . $val . ')');
-
- $res;
-}
-
-1;
-
-=head1 BUGS
-
-None known
-
-=head1 AUTHOR
-
-Jonathan Kew L<Jonathan_Kew at sil.org>. See L<Font::TTF::Font> for copyright and
-licensing.
-
-=cut
-
+package Font::TTF::Mort::Chain;
+
+=head1 NAME
+
+Font::TTF::Mort::Chain
+
+=cut
+
+use strict;
+use Font::TTF::Utils;
+use Font::TTF::AATutils;
+use Font::TTF::Mort::Subtable;
+use IO::File;
+
+=head2 $t->new
+
+=cut
+
+sub new
+{
+ my ($class, %parms) = @_;
+ my ($self) = {};
+ my ($p);
+
+ $class = ref($class) || $class;
+ foreach $p (keys %parms)
+ { $self->{" $p"} = $parms{$p}; }
+ bless $self, $class;
+}
+
+=head2 $t->read($fh)
+
+Reads the chain into memory
+
+=cut
+
+sub read
+{
+ my ($self, $fh) = @_;
+ my ($dat);
+
+ my $chainStart = $fh->tell();
+ $fh->read($dat, 12);
+ my ($defaultFlags, $chainLength, $nFeatureEntries, $nSubtables) = TTF_Unpack("LLSS", $dat);
+
+ my $featureEntries = [];
+ foreach (1 .. $nFeatureEntries) {
+ $fh->read($dat, 12);
+ my ($featureType, $featureSetting, $enableFlags, $disableFlags) = TTF_Unpack("SSLL", $dat);
+ push @$featureEntries, {
+ 'type' => $featureType,
+ 'setting' => $featureSetting,
+ 'enable' => $enableFlags,
+ 'disable' => $disableFlags
+ };
+ }
+
+ my $subtables = [];
+ foreach (1 .. $nSubtables) {
+ my $subtableStart = $fh->tell();
+
+ $fh->read($dat, 8);
+ my ($length, $coverage, $subFeatureFlags) = TTF_Unpack("SSL", $dat);
+ my $type = $coverage & 0x0007;
+
+ my $subtable = Font::TTF::Mort::Subtable->create($type, $coverage, $subFeatureFlags, $length);
+ $subtable->read($fh);
+ $subtable->{' PARENT'} = $self;
+
+ push @$subtables, $subtable;
+ $fh->seek($subtableStart + $length, IO::File::SEEK_SET);
+ }
+
+ $self->{'defaultFlags'} = $defaultFlags;
+ $self->{'featureEntries'} = $featureEntries;
+ $self->{'subtables'} = $subtables;
+
+ $fh->seek($chainStart + $chainLength, IO::File::SEEK_SET);
+
+ $self;
+}
+
+=head2 $t->out($fh)
+
+Writes the table to a file either from memory or by copying
+
+=cut
+
+sub out
+{
+ my ($self, $fh) = @_;
+
+ my $chainStart = $fh->tell();
+ my ($featureEntries, $subtables) = ($_->{'featureEntries'}, $_->{'subtables'});
+ $fh->print(TTF_Pack("LLSS", $_->{'defaultFlags'}, 0, scalar @$featureEntries, scalar @$subtables)); # placeholder for length
+
+ foreach (@$featureEntries) {
+ $fh->print(TTF_Pack("SSLL", $_->{'type'}, $_->{'setting'}, $_->{'enable'}, $_->{'disable'}));
+ }
+
+ foreach (@$subtables) {
+ $_->out($fh);
+ }
+
+ my $chainLength = $fh->tell() - $chainStart;
+ $fh->seek($chainStart + 4, IO::File::SEEK_SET);
+ $fh->print(pack("N", $chainLength));
+ $fh->seek($chainStart + $chainLength, IO::File::SEEK_SET);
+}
+
+=head2 $t->print($fh)
+
+Prints a human-readable representation of the chain
+
+=cut
+
+sub feat
+{
+ my ($self) = @_;
+
+ my $feat = $self->{' PARENT'}{' PARENT'}{'feat'};
+ if (defined $feat) {
+ $feat->read;
+ }
+ else {
+ $feat = {};
+ }
+
+ return $feat;
+}
+
+sub print
+{
+ my ($self, $fh) = @_;
+
+ $fh->printf("version %f\n", $self->{'version'});
+
+ my $defaultFlags = $self->{'defaultFlags'};
+ $fh->printf("chain: defaultFlags = %08x\n", $defaultFlags);
+
+ my $feat = $self->feat();
+ my $featureEntries = $self->{'featureEntries'};
+ foreach (@$featureEntries) {
+ $fh->printf("\tfeature %d, setting %d : enableFlags = %08x, disableFlags = %08x # '%s: %s'\n",
+ $_->{'type'}, $_->{'setting'}, $_->{'enable'}, $_->{'disable'},
+ $feat->settingName($_->{'type'}, $_->{'setting'}));
+ }
+
+ my $subtables = $self->{'subtables'};
+ foreach (@$subtables) {
+ my $type = $_->{'type'};
+ my $subFeatureFlags = $_->{'subFeatureFlags'};
+ $fh->printf("\n\t%s table, %s, %s, subFeatureFlags = %08x # %s (%s)\n",
+ subtable_type_($type), $_->{'direction'}, $_->{'orientation'}, $subFeatureFlags,
+ "Default " . ((($subFeatureFlags & $defaultFlags) != 0) ? "On" : "Off"),
+ join(", ",
+ map {
+ join(": ", $feat->settingName($_->{'type'}, $_->{'setting'}) )
+ } grep { ($_->{'enable'} & $subFeatureFlags) != 0 } @$featureEntries
+ ) );
+
+ $_->print($fh);
+ }
+}
+
+sub subtable_type_
+{
+ my ($val) = @_;
+ my ($res);
+
+ my @types = (
+ 'Rearrangement',
+ 'Contextual',
+ 'Ligature',
+ undef,
+ 'Non-contextual',
+ 'Insertion',
+ );
+ $res = $types[$val] or ('Undefined (' . $val . ')');
+
+ $res;
+}
+
+1;
+
+=head1 BUGS
+
+None known
+
+=head1 AUTHOR
+
+Jonathan Kew L<Jonathan_Kew at sil.org>. See L<Font::TTF::Font> for copyright and
+licensing.
+
+=cut
+
Modified: packages/libfont-ttf-perl/trunk/lib/Font/TTF/Mort/Contextual.pm
===================================================================
--- packages/libfont-ttf-perl/trunk/lib/Font/TTF/Mort/Contextual.pm 2006-01-17 02:56:43 UTC (rev 1966)
+++ packages/libfont-ttf-perl/trunk/lib/Font/TTF/Mort/Contextual.pm 2006-01-17 03:07:20 UTC (rev 1967)
@@ -1,156 +1,157 @@
-package Font::TTF::Mort::Contextual;
-
-=head1 NAME
-
-Font::TTF::Mort::Contextual
-
-=head1 METHODS
-
-=cut
-
-use strict;
-use vars qw(@ISA);
-use Font::TTF::Utils;
-use Font::TTF::AATutils;
-use Font::TTF::Mort::Subtable;
-
- at ISA = qw(Font::TTF::AAT::Mort::Subtable);
-
-sub new
-{
- my ($class, $direction, $orientation, $subFeatureFlags) = @_;
- my ($self) = {
- 'direction' => $direction,
- 'orientation' => $orientation,
- 'subFeatureFlags' => $subFeatureFlags
- };
-
- $class = ref($class) || $class;
- bless $self, $class;
-}
-
-=head2 $t->read
-
-Reads the table into memory
-
-=cut
-
-sub read
-{
- my ($self, $fh) = @_;
- my ($dat);
-
- my $stateTableStart = $fh->tell();
- my ($classes, $states, $entries) = AAT_read_state_table($fh, 2);
-
- $fh->seek($stateTableStart, IO::File::SEEK_SET);
- $fh->read($dat, 10);
- my ($stateSize, $classTable, $stateArray, $entryTable, $mappingTables) = unpack("nnnnn", $dat);
- my $limits = [$classTable, $stateArray, $entryTable, $mappingTables, $self->{'length'} - 8];
-
- foreach (@$entries) {
- my $actions = $_->{'actions'};
- foreach (@$actions) {
- $_ = $_ ? $_ - ($mappingTables / 2) : undef;
- }
- }
-
- $self->{'classes'} = $classes;
- $self->{'states'} = $states;
- $self->{'mappings'} = [unpack("n*", AAT_read_subtable($fh, $stateTableStart, $mappingTables, $limits))];
-
- $self;
-}
-
-=head2 $t->pack_sub()
-
-=cut
-
-sub pack_sub
-{
- my ($self) = @_;
-
- my ($dat) = pack("nnnnn", (0) x 5); # placeholders for stateSize, classTable, stateArray, entryTable, mappingTables
-
- my $classTable = length($dat);
- my $classes = $self->{'classes'};
- $dat .= AAT_pack_classes($classes);
-
- my $stateArray = length($dat);
- my $states = $self->{'states'};
- my ($dat1, $stateSize, $entries) = AAT_pack_states($classes, $stateArray, $states,
- sub {
- my $actions = $_->{'actions'};
- ( $_->{'flags'}, @$actions )
- }
- );
- $dat .= $dat1;
-
- my $entryTable = length($dat);
- my $offset = ($entryTable + 8 * @$entries) / 2;
- foreach (@$entries) {
- my ($nextState, $flags, @parts) = split /,/;
- $dat .= pack("nnnn", $nextState, $flags, map { $_ eq "" ? 0 : $_ + $offset } @parts);
- }
-
- my $mappingTables = length($dat);
- my $mappings = $self->{'mappings'};
- $dat .= pack("n*", @$mappings);
-
- $dat1 = pack("nnnnn", $stateSize, $classTable, $stateArray, $entryTable, $mappingTables);
- substr($dat, 0, length($dat1)) = $dat1;
-
- return $dat;
-}
-
-=head2 $t->print($fh)
-
-Prints a human-readable representation of the table
-
-=cut
-
-sub print
-{
- my ($self, $fh) = @_;
-
- my $post = $self->post();
-
- $fh = 'STDOUT' unless defined $fh;
-
- $self->print_classes($fh);
-
- $fh->print("\n");
- my $states = $self->{'states'};
- foreach (0 .. $#$states) {
- $fh->printf("\t\tState %d:", $_);
- my $state = $states->[$_];
- foreach (@$state) {
- my $flags;
- $flags .= "!" if ($_->{'flags'} & 0x4000);
- $flags .= "*" if ($_->{'flags'} & 0x8000);
- my $actions = $_->{'actions'};
- $fh->printf("\t(%s%d,%s,%s)", $flags, $_->{'nextState'}, map { defined $_ ? $_ : "=" } @$actions);
- }
- $fh->print("\n");
- }
-
- $fh->print("\n");
- my $mappings = $self->{'mappings'};
- foreach (0 .. $#$mappings) {
- $fh->printf("\t\tMapping %d: %d [%s]\n", $_, $mappings->[$_], $post->{'VAL'}[$mappings->[$_]]);
- }
-}
-
-1;
-
-=head1 BUGS
-
-None known
-
-=head1 AUTHOR
-
-Jonathan Kew L<Jonathan_Kew at sil.org>. See L<Font::TTF::Font> for copyright and
-licensing.
-
-=cut
-
+package Font::TTF::Mort::Contextual;
+
+=head1 NAME
+
+Font::TTF::Mort::Contextual
+
+=head1 METHODS
+
+=cut
+
+use strict;
+use vars qw(@ISA);
+use Font::TTF::Utils;
+use Font::TTF::AATutils;
+use Font::TTF::Mort::Subtable;
+use IO::File;
+
+ at ISA = qw(Font::TTF::AAT::Mort::Subtable);
+
+sub new
+{
+ my ($class, $direction, $orientation, $subFeatureFlags) = @_;
+ my ($self) = {
+ 'direction' => $direction,
+ 'orientation' => $orientation,
+ 'subFeatureFlags' => $subFeatureFlags
+ };
+
+ $class = ref($class) || $class;
+ bless $self, $class;
+}
+
+=head2 $t->read
+
+Reads the table into memory
+
+=cut
+
+sub read
+{
+ my ($self, $fh) = @_;
+ my ($dat);
+
+ my $stateTableStart = $fh->tell();
+ my ($classes, $states, $entries) = AAT_read_state_table($fh, 2);
+
+ $fh->seek($stateTableStart, IO::File::SEEK_SET);
+ $fh->read($dat, 10);
+ my ($stateSize, $classTable, $stateArray, $entryTable, $mappingTables) = unpack("nnnnn", $dat);
+ my $limits = [$classTable, $stateArray, $entryTable, $mappingTables, $self->{'length'} - 8];
+
+ foreach (@$entries) {
+ my $actions = $_->{'actions'};
+ foreach (@$actions) {
+ $_ = $_ ? $_ - ($mappingTables / 2) : undef;
+ }
+ }
+
+ $self->{'classes'} = $classes;
+ $self->{'states'} = $states;
+ $self->{'mappings'} = [unpack("n*", AAT_read_subtable($fh, $stateTableStart, $mappingTables, $limits))];
+
+ $self;
+}
+
+=head2 $t->pack_sub()
+
+=cut
+
+sub pack_sub
+{
+ my ($self) = @_;
+
+ my ($dat) = pack("nnnnn", (0) x 5); # placeholders for stateSize, classTable, stateArray, entryTable, mappingTables
+
+ my $classTable = length($dat);
+ my $classes = $self->{'classes'};
+ $dat .= AAT_pack_classes($classes);
+
+ my $stateArray = length($dat);
+ my $states = $self->{'states'};
+ my ($dat1, $stateSize, $entries) = AAT_pack_states($classes, $stateArray, $states,
+ sub {
+ my $actions = $_->{'actions'};
+ ( $_->{'flags'}, @$actions )
+ }
+ );
+ $dat .= $dat1;
+
+ my $entryTable = length($dat);
+ my $offset = ($entryTable + 8 * @$entries) / 2;
+ foreach (@$entries) {
+ my ($nextState, $flags, @parts) = split /,/;
+ $dat .= pack("nnnn", $nextState, $flags, map { $_ eq "" ? 0 : $_ + $offset } @parts);
+ }
+
+ my $mappingTables = length($dat);
+ my $mappings = $self->{'mappings'};
+ $dat .= pack("n*", @$mappings);
+
+ $dat1 = pack("nnnnn", $stateSize, $classTable, $stateArray, $entryTable, $mappingTables);
+ substr($dat, 0, length($dat1)) = $dat1;
+
+ return $dat;
+}
+
+=head2 $t->print($fh)
+
+Prints a human-readable representation of the table
+
+=cut
+
+sub print
+{
+ my ($self, $fh) = @_;
+
+ my $post = $self->post();
+
+ $fh = 'STDOUT' unless defined $fh;
+
+ $self->print_classes($fh);
+
+ $fh->print("\n");
+ my $states = $self->{'states'};
+ foreach (0 .. $#$states) {
+ $fh->printf("\t\tState %d:", $_);
+ my $state = $states->[$_];
+ foreach (@$state) {
+ my $flags;
+ $flags .= "!" if ($_->{'flags'} & 0x4000);
+ $flags .= "*" if ($_->{'flags'} & 0x8000);
+ my $actions = $_->{'actions'};
+ $fh->printf("\t(%s%d,%s,%s)", $flags, $_->{'nextState'}, map { defined $_ ? $_ : "=" } @$actions);
+ }
+ $fh->print("\n");
+ }
+
+ $fh->print("\n");
+ my $mappings = $self->{'mappings'};
+ foreach (0 .. $#$mappings) {
+ $fh->printf("\t\tMapping %d: %d [%s]\n", $_, $mappings->[$_], $post->{'VAL'}[$mappings->[$_]]);
+ }
+}
+
+1;
+
+=head1 BUGS
+
+None known
+
+=head1 AUTHOR
+
+Jonathan Kew L<Jonathan_Kew at sil.org>. See L<Font::TTF::Font> for copyright and
+licensing.
+
+=cut
+
Modified: packages/libfont-ttf-perl/trunk/lib/Font/TTF/Mort/Insertion.pm
===================================================================
--- packages/libfont-ttf-perl/trunk/lib/Font/TTF/Mort/Insertion.pm 2006-01-17 02:56:43 UTC (rev 1966)
+++ packages/libfont-ttf-perl/trunk/lib/Font/TTF/Mort/Insertion.pm 2006-01-17 03:07:20 UTC (rev 1967)
@@ -1,178 +1,179 @@
-package Font::TTF::Mort::Insertion;
-
-=head1 NAME
-
-Font::TTF::Mort::Insertion
-
-=head1 METHODS
-
-=cut
-
-use strict;
-use vars qw(@ISA);
-use Font::TTF::Utils;
-use Font::TTF::AATutils;
-
- at ISA = qw(Font::TTF::Mort::Subtable);
-
-sub new
-{
- my ($class, $direction, $orientation, $subFeatureFlags) = @_;
- my ($self) = {
- 'direction' => $direction,
- 'orientation' => $orientation,
- 'subFeatureFlags' => $subFeatureFlags
- };
-
- $class = ref($class) || $class;
- bless $self, $class;
-}
-
-=head2 $t->read
-
-Reads the table into memory
-
-=cut
-
-sub read
-{
- my ($self, $fh) = @_;
- my ($dat);
-
- my $subtableStart = $fh->tell();
-
- my $stateTableStart = $fh->tell();
- my ($classes, $states, $entries) = AAT_read_state_table($fh, 2);
-
- my %insertListHash;
- my $insertLists;
- foreach (@$entries) {
- my $flags = $_->{'flags'};
- my @insertCount = (($flags & 0x03e0) >> 5, ($flags & 0x001f));
- my $actions = $_->{'actions'};
- foreach (0 .. 1) {
- if ($insertCount[$_] > 0) {
- $fh->seek($stateTableStart + $actions->[$_], IO::File::SEEK_SET);
- $fh->read($dat, $insertCount[$_] * 2);
- if (not defined $insertListHash{$dat}) {
- push @$insertLists, [unpack("n*", $dat)];
- $insertListHash{$dat} = $#$insertLists;
- }
- $actions->[$_] = $insertListHash{$dat};
- }
- else {
- $actions->[$_] = undef;
- }
- }
- }
-
- $self->{'classes'} = $classes;
- $self->{'states'} = $states;
- $self->{'insertLists'} = $insertLists;
-
- $self;
-}
-
-=head2 $t->pack_sub()
-
-=cut
-
-sub pack_sub
-{
- my ($self) = @_;
-
- my ($dat) = pack("nnnn", (0) x 4);
-
- my $classTable = length($dat);
- my $classes = $self->{'classes'};
- $dat .= AAT_pack_classes($classes);
-
- my $stateArray = length($dat);
- my $states = $self->{'states'};
- my ($dat1, $stateSize, $entries) = AAT_pack_states($classes, $stateArray, $states,
- sub {
- my $actions = $_->{'actions'};
- ( $_->{'flags'}, @$actions )
- }
- );
- $dat .= $dat1;
-
- my $entryTable = length($dat);
- my $offset = ($entryTable + 8 * @$entries);
- my @insListOffsets;
- my $insertLists = $self->{'insertLists'};
- foreach (@$insertLists) {
- push @insListOffsets, $offset;
- $offset += 2 * scalar @$_;
- }
- foreach (@$entries) {
- my ($nextState, $flags, @lists) = split /,/;
- $flags &= ~0x03ff;
- $flags |= (scalar @{$insertLists->[$lists[0]]}) << 5 if $lists[0] ne '';
- $flags |= (scalar @{$insertLists->[$lists[1]]}) if $lists[1] ne '';
- $dat .= pack("nnnn", $nextState, $flags,
- map { $_ eq '' ? 0 : $insListOffsets[$_] } @lists);
- }
-
- foreach (@$insertLists) {
- $dat .= pack("n*", @$_);
- }
-
- $dat1 = pack("nnnn", $stateSize, $classTable, $stateArray, $entryTable);
- substr($dat, 0, length($dat1)) = $dat1;
-
- return $dat;
-}
-
-=head2 $t->print($fh)
-
-Prints a human-readable representation of the table
-
-=cut
-
-sub print
-{
- my ($self, $fh) = @_;
-
- my $post = $self->post();
-
- $fh = 'STDOUT' unless defined $fh;
-
- $self->print_classes($fh);
-
- $fh->print("\n");
- my $states = $self->{'states'};
- foreach (0 .. $#$states) {
- $fh->printf("\t\tState %d:", $_);
- my $state = $states->[$_];
- foreach (@$state) {
- my $flags;
- $flags .= "!" if ($_->{'flags'} & 0x4000);
- $flags .= "*" if ($_->{'flags'} & 0x8000);
- my $actions = $_->{'actions'};
- $fh->printf("\t(%s%d,%s,%s)", $flags, $_->{'nextState'}, map { defined $_ ? $_ : "=" } @$actions);
- }
- $fh->print("\n");
- }
-
- $fh->print("\n");
- my $insertLists = $self->{'insertLists'};
- foreach (0 .. $#$insertLists) {
- my $insertList = $insertLists->[$_];
- $fh->printf("\t\tList %d: %s\n", $_, join(", ", map { $_ . " [" . $post->{'VAL'}[$_] . "]" } @$insertList));
- }
-}
-
-1;
-
-=head1 BUGS
-
-None known
-
-=head1 AUTHOR
-
-Jonathan Kew L<Jonathan_Kew at sil.org>. See L<Font::TTF::Font> for copyright and
-licensing.
-
-=cut
-
+package Font::TTF::Mort::Insertion;
+
+=head1 NAME
+
+Font::TTF::Mort::Insertion
+
+=head1 METHODS
+
+=cut
+
+use strict;
+use vars qw(@ISA);
+use Font::TTF::Utils;
+use Font::TTF::AATutils;
+use IO::File;
+
+ at ISA = qw(Font::TTF::Mort::Subtable);
+
+sub new
+{
+ my ($class, $direction, $orientation, $subFeatureFlags) = @_;
+ my ($self) = {
+ 'direction' => $direction,
+ 'orientation' => $orientation,
+ 'subFeatureFlags' => $subFeatureFlags
+ };
+
+ $class = ref($class) || $class;
+ bless $self, $class;
+}
+
+=head2 $t->read
+
+Reads the table into memory
+
+=cut
+
+sub read
+{
+ my ($self, $fh) = @_;
+ my ($dat);
+
+ my $subtableStart = $fh->tell();
+
+ my $stateTableStart = $fh->tell();
+ my ($classes, $states, $entries) = AAT_read_state_table($fh, 2);
+
+ my %insertListHash;
+ my $insertLists;
+ foreach (@$entries) {
+ my $flags = $_->{'flags'};
+ my @insertCount = (($flags & 0x03e0) >> 5, ($flags & 0x001f));
+ my $actions = $_->{'actions'};
+ foreach (0 .. 1) {
+ if ($insertCount[$_] > 0) {
+ $fh->seek($stateTableStart + $actions->[$_], IO::File::SEEK_SET);
+ $fh->read($dat, $insertCount[$_] * 2);
+ if (not defined $insertListHash{$dat}) {
+ push @$insertLists, [unpack("n*", $dat)];
+ $insertListHash{$dat} = $#$insertLists;
+ }
+ $actions->[$_] = $insertListHash{$dat};
+ }
+ else {
+ $actions->[$_] = undef;
+ }
+ }
+ }
+
+ $self->{'classes'} = $classes;
+ $self->{'states'} = $states;
+ $self->{'insertLists'} = $insertLists;
+
+ $self;
+}
+
+=head2 $t->pack_sub()
+
+=cut
+
+sub pack_sub
+{
+ my ($self) = @_;
+
+ my ($dat) = pack("nnnn", (0) x 4);
+
+ my $classTable = length($dat);
+ my $classes = $self->{'classes'};
+ $dat .= AAT_pack_classes($classes);
+
+ my $stateArray = length($dat);
+ my $states = $self->{'states'};
+ my ($dat1, $stateSize, $entries) = AAT_pack_states($classes, $stateArray, $states,
+ sub {
+ my $actions = $_->{'actions'};
+ ( $_->{'flags'}, @$actions )
+ }
+ );
+ $dat .= $dat1;
+
+ my $entryTable = length($dat);
+ my $offset = ($entryTable + 8 * @$entries);
+ my @insListOffsets;
+ my $insertLists = $self->{'insertLists'};
+ foreach (@$insertLists) {
+ push @insListOffsets, $offset;
+ $offset += 2 * scalar @$_;
+ }
+ foreach (@$entries) {
+ my ($nextState, $flags, @lists) = split /,/;
+ $flags &= ~0x03ff;
+ $flags |= (scalar @{$insertLists->[$lists[0]]}) << 5 if $lists[0] ne '';
+ $flags |= (scalar @{$insertLists->[$lists[1]]}) if $lists[1] ne '';
+ $dat .= pack("nnnn", $nextState, $flags,
+ map { $_ eq '' ? 0 : $insListOffsets[$_] } @lists);
+ }
+
+ foreach (@$insertLists) {
+ $dat .= pack("n*", @$_);
+ }
+
+ $dat1 = pack("nnnn", $stateSize, $classTable, $stateArray, $entryTable);
+ substr($dat, 0, length($dat1)) = $dat1;
+
+ return $dat;
+}
+
+=head2 $t->print($fh)
+
+Prints a human-readable representation of the table
+
+=cut
+
+sub print
+{
+ my ($self, $fh) = @_;
+
+ my $post = $self->post();
+
+ $fh = 'STDOUT' unless defined $fh;
+
+ $self->print_classes($fh);
+
+ $fh->print("\n");
+ my $states = $self->{'states'};
+ foreach (0 .. $#$states) {
+ $fh->printf("\t\tState %d:", $_);
+ my $state = $states->[$_];
+ foreach (@$state) {
+ my $flags;
+ $flags .= "!" if ($_->{'flags'} & 0x4000);
+ $flags .= "*" if ($_->{'flags'} & 0x8000);
+ my $actions = $_->{'actions'};
+ $fh->printf("\t(%s%d,%s,%s)", $flags, $_->{'nextState'}, map { defined $_ ? $_ : "=" } @$actions);
+ }
+ $fh->print("\n");
+ }
+
+ $fh->print("\n");
+ my $insertLists = $self->{'insertLists'};
+ foreach (0 .. $#$insertLists) {
+ my $insertList = $insertLists->[$_];
+ $fh->printf("\t\tList %d: %s\n", $_, join(", ", map { $_ . " [" . $post->{'VAL'}[$_] . "]" } @$insertList));
+ }
+}
+
+1;
+
+=head1 BUGS
+
+None known
+
+=head1 AUTHOR
+
+Jonathan Kew L<Jonathan_Kew at sil.org>. See L<Font::TTF::Font> for copyright and
+licensing.
+
+=cut
+
Modified: packages/libfont-ttf-perl/trunk/lib/Font/TTF/Mort/Ligature.pm
===================================================================
--- packages/libfont-ttf-perl/trunk/lib/Font/TTF/Mort/Ligature.pm 2006-01-17 02:56:43 UTC (rev 1966)
+++ packages/libfont-ttf-perl/trunk/lib/Font/TTF/Mort/Ligature.pm 2006-01-17 03:07:20 UTC (rev 1967)
@@ -1,245 +1,246 @@
-package Font::TTF::Mort::Ligature;
-
-=head1 NAME
-
-Font::TTF::Mort::Ligature
-
-=head1 METHODS
-
-=cut
-
-use strict;
-use vars qw(@ISA);
-use Font::TTF::Utils;
-use Font::TTF::AATutils;
-
- at ISA = qw(Font::TTF::Mort::Subtable);
-
-sub new
-{
- my ($class, $direction, $orientation, $subFeatureFlags) = @_;
- my ($self) = {
- 'direction' => $direction,
- 'orientation' => $orientation,
- 'subFeatureFlags' => $subFeatureFlags
- };
-
- $class = ref($class) || $class;
- bless $self, $class;
-}
-
-=head2 $t->read
-
-Reads the table into memory
-
-=cut
-
-sub read
-{
- my ($self, $fh) = @_;
- my ($dat);
-
- my $stateTableStart = $fh->tell();
- my ($classes, $states, $entries) = AAT_read_state_table($fh, 0);
-
- $fh->seek($stateTableStart, IO::File::SEEK_SET);
- $fh->read($dat, 14);
- my ($stateSize, $classTable, $stateArray, $entryTable,
- $ligActionTable, $componentTable, $ligatureTable) = unpack("nnnnnnn", $dat);
- my $limits = [$classTable, $stateArray, $entryTable, $ligActionTable, $componentTable, $ligatureTable, $self->{'length'} - 8];
-
- my %actions;
- my $actionLists;
- foreach (@$entries) {
- my $offset = $_->{'flags'} & 0x3fff;
- $_->{'flags'} &= ~0x3fff;
- if ($offset != 0) {
- if (not defined $actions{$offset}) {
- $fh->seek($stateTableStart + $offset, IO::File::SEEK_SET);
- my $actionList;
- while (1) {
- $fh->read($dat, 4);
- my $action = unpack("N", $dat);
- my ($last, $store, $component) = (($action & 0x80000000) != 0, ($action & 0xC0000000) != 0, ($action & 0x3fffffff));
- $component -= 0x40000000 if $component > 0x1fffffff;
- $component -= $componentTable / 2;
- push @$actionList, { 'store' => $store, 'component' => $component };
- last if $last;
- }
- push @$actionLists, $actionList;
- $actions{$offset} = $#$actionLists;
- }
- $_->{'actions'} = $actions{$offset};
- }
- }
-
- $self->{'componentTable'} = $componentTable;
- my $components = [unpack("n*", AAT_read_subtable($fh, $stateTableStart, $componentTable, $limits))];
- foreach (@$components) {
- $_ = ($_ - $ligatureTable) . " +" if $_ >= $ligatureTable;
- }
- $self->{'components'} = $components;
-
- $self->{'ligatureTable'} = $ligatureTable;
- $self->{'ligatures'} = [unpack("n*", AAT_read_subtable($fh, $stateTableStart, $ligatureTable, $limits))];
-
- $self->{'classes'} = $classes;
- $self->{'states'} = $states;
- $self->{'actionLists'} = $actionLists;
-
- $self;
-}
-
-=head2 $t->pack_sub($fh)
-
-=cut
-
-sub pack_sub
-{
- my ($self) = @_;
- my ($dat);
-
- $dat .= pack("nnnnnnn", (0) x 7); # placeholders for stateSize, classTable, stateArray, entryTable, actionLists, components, ligatures
-
- my $classTable = length($dat);
- my $classes = $self->{'classes'};
- $dat .= AAT_pack_classes($classes);
-
- my $stateArray = length($dat);
- my $states = $self->{'states'};
-
- my ($dat1, $stateSize, $entries) = AAT_pack_states($classes, $stateArray, $states,
- sub {
- ( $_->{'flags'} & 0xc000, $_->{'actions'} )
- }
- );
- $dat .= $dat1;
-
- my $actionLists = $self->{'actionLists'};
- my %actionListOffset;
- my $actionListDataLength = 0;
- my @actionListEntries;
- foreach (0 .. $#$entries) {
- my ($nextState, $flags, $offset) = split(/,/, $entries->[$_]);
- if ($offset eq "") {
- $offset = undef;
- }
- else {
- if (defined $actionListOffset{$offset}) {
- $offset = $actionListOffset{$offset};
- }
- else {
- $actionListOffset{$offset} = $actionListDataLength;
- my $list = $actionLists->[$offset];
- $actionListDataLength += 4 * @$list;
- push @actionListEntries, $list;
- $offset = $actionListOffset{$offset};
- }
- }
- $entries->[$_] = [ $nextState, $flags, $offset ];
- }
- my $entryTable = length($dat);
- my $ligActionLists = ($entryTable + @$entries * 4 + 3) & ~3;
- foreach (@$entries) {
- $_->[2] += $ligActionLists if defined $_->[2];
- $dat .= pack("nn", $_->[0], $_->[1] + $_->[2]);
- }
- $dat .= pack("C*", (0) x ($ligActionLists - $entryTable - @$entries * 4));
-
- die "internal error" unless length($dat) == $ligActionLists;
-
- my $componentTable = length($dat) + $actionListDataLength;
- my $actionList;
- foreach $actionList (@actionListEntries) {
- foreach (0 .. $#$actionList) {
- my $action = $actionList->[$_];
- my $val = $action->{'component'} + $componentTable / 2;
- $val += 0x40000000 if $val < 0;
- $val &= 0x3fffffff;
- $val |= 0x40000000 if $action->{'store'};
- $val |= 0x80000000 if $_ == $#$actionList;
- $dat .= pack("N", $val);
- }
- }
-
- die "internal error" unless length($dat) == $componentTable;
-
- my $components = $self->{'components'};
- my $ligatureTable = $componentTable + @$components * 2;
- $dat .= pack("n*", map { (index($_, '+') >= 0 ? $ligatureTable : 0) + $_ } @$components);
-
- my $ligatures = $self->{'ligatures'};
- $dat .= pack("n*", @$ligatures);
-
- $dat1 = pack("nnnnnnn", $stateSize, $classTable, $stateArray, $entryTable, $ligActionLists, $componentTable, $ligatureTable);
- substr($dat, 0, length($dat1)) = $dat1;
-
- return $dat;
-}
-
-=head2 $t->print($fh)
-
-Prints a human-readable representation of the table
-
-=cut
-
-sub print
-{
- my ($self, $fh) = @_;
-
- my $post = $self->post();
-
- $fh = 'STDOUT' unless defined $fh;
-
- $self->print_classes($fh);
-
- $fh->print("\n");
- my $states = $self->{'states'};
- foreach (0 .. $#$states) {
- $fh->printf("\t\tState %d:", $_);
- my $state = $states->[$_];
- foreach (@$state) {
- my $flags;
- $flags .= "!" if ($_->{'flags'} & 0x4000);
- $flags .= "*" if ($_->{'flags'} & 0x8000);
- $fh->printf("\t(%s%d,%s)", $flags, $_->{'nextState'}, defined $_->{'actions'} ? $_->{'actions'} : "=");
- }
- $fh->print("\n");
- }
-
- $fh->print("\n");
- my $actionLists = $self->{'actionLists'};
- foreach (0 .. $#$actionLists) {
- $fh->printf("\t\tList %d:\t", $_);
- my $actionList = $actionLists->[$_];
- $fh->printf("%s\n", join(", ", map { ($_->{'component'} . ($_->{'store'} ? "*" : "") ) } @$actionList));
- }
-
- my $ligatureTable = $self->{'ligatureTable'};
-
- $fh->print("\n");
- my $components = $self->{'components'};
- foreach (0 .. $#$components) {
- $fh->printf("\t\tComponent %d: %s\n", $_, $components->[$_]);
- }
-
- $fh->print("\n");
- my $ligatures = $self->{'ligatures'};
- foreach (0 .. $#$ligatures) {
- $fh->printf("\t\tLigature %d: %d [%s]\n", $_, $ligatures->[$_], $post->{'VAL'}[$ligatures->[$_]]);
- }
-}
-
-1;
-
-=head1 BUGS
-
-None known
-
-=head1 AUTHOR
-
-Jonathan Kew L<Jonathan_Kew at sil.org>. See L<Font::TTF::Font> for copyright and
-licensing.
-
-=cut
-
+package Font::TTF::Mort::Ligature;
+
+=head1 NAME
+
+Font::TTF::Mort::Ligature
+
+=head1 METHODS
+
+=cut
+
+use strict;
+use vars qw(@ISA);
+use Font::TTF::Utils;
+use Font::TTF::AATutils;
+use IO::File;
+
+ at ISA = qw(Font::TTF::Mort::Subtable);
+
+sub new
+{
+ my ($class, $direction, $orientation, $subFeatureFlags) = @_;
+ my ($self) = {
+ 'direction' => $direction,
+ 'orientation' => $orientation,
+ 'subFeatureFlags' => $subFeatureFlags
+ };
+
+ $class = ref($class) || $class;
+ bless $self, $class;
+}
+
+=head2 $t->read
+
+Reads the table into memory
+
+=cut
+
+sub read
+{
+ my ($self, $fh) = @_;
+ my ($dat);
+
+ my $stateTableStart = $fh->tell();
+ my ($classes, $states, $entries) = AAT_read_state_table($fh, 0);
+
+ $fh->seek($stateTableStart, IO::File::SEEK_SET);
+ $fh->read($dat, 14);
+ my ($stateSize, $classTable, $stateArray, $entryTable,
+ $ligActionTable, $componentTable, $ligatureTable) = unpack("nnnnnnn", $dat);
+ my $limits = [$classTable, $stateArray, $entryTable, $ligActionTable, $componentTable, $ligatureTable, $self->{'length'} - 8];
+
+ my %actions;
+ my $actionLists;
+ foreach (@$entries) {
+ my $offset = $_->{'flags'} & 0x3fff;
+ $_->{'flags'} &= ~0x3fff;
+ if ($offset != 0) {
+ if (not defined $actions{$offset}) {
+ $fh->seek($stateTableStart + $offset, IO::File::SEEK_SET);
+ my $actionList;
+ while (1) {
+ $fh->read($dat, 4);
+ my $action = unpack("N", $dat);
+ my ($last, $store, $component) = (($action & 0x80000000) != 0, ($action & 0xC0000000) != 0, ($action & 0x3fffffff));
+ $component -= 0x40000000 if $component > 0x1fffffff;
+ $component -= $componentTable / 2;
+ push @$actionList, { 'store' => $store, 'component' => $component };
+ last if $last;
+ }
+ push @$actionLists, $actionList;
+ $actions{$offset} = $#$actionLists;
+ }
+ $_->{'actions'} = $actions{$offset};
+ }
+ }
+
+ $self->{'componentTable'} = $componentTable;
+ my $components = [unpack("n*", AAT_read_subtable($fh, $stateTableStart, $componentTable, $limits))];
+ foreach (@$components) {
+ $_ = ($_ - $ligatureTable) . " +" if $_ >= $ligatureTable;
+ }
+ $self->{'components'} = $components;
+
+ $self->{'ligatureTable'} = $ligatureTable;
+ $self->{'ligatures'} = [unpack("n*", AAT_read_subtable($fh, $stateTableStart, $ligatureTable, $limits))];
+
+ $self->{'classes'} = $classes;
+ $self->{'states'} = $states;
+ $self->{'actionLists'} = $actionLists;
+
+ $self;
+}
+
+=head2 $t->pack_sub($fh)
+
+=cut
+
+sub pack_sub
+{
+ my ($self) = @_;
+ my ($dat);
+
+ $dat .= pack("nnnnnnn", (0) x 7); # placeholders for stateSize, classTable, stateArray, entryTable, actionLists, components, ligatures
+
+ my $classTable = length($dat);
+ my $classes = $self->{'classes'};
+ $dat .= AAT_pack_classes($classes);
+
+ my $stateArray = length($dat);
+ my $states = $self->{'states'};
+
+ my ($dat1, $stateSize, $entries) = AAT_pack_states($classes, $stateArray, $states,
+ sub {
+ ( $_->{'flags'} & 0xc000, $_->{'actions'} )
+ }
+ );
+ $dat .= $dat1;
+
+ my $actionLists = $self->{'actionLists'};
+ my %actionListOffset;
+ my $actionListDataLength = 0;
+ my @actionListEntries;
+ foreach (0 .. $#$entries) {
+ my ($nextState, $flags, $offset) = split(/,/, $entries->[$_]);
+ if ($offset eq "") {
+ $offset = undef;
+ }
+ else {
+ if (defined $actionListOffset{$offset}) {
+ $offset = $actionListOffset{$offset};
+ }
+ else {
+ $actionListOffset{$offset} = $actionListDataLength;
+ my $list = $actionLists->[$offset];
+ $actionListDataLength += 4 * @$list;
+ push @actionListEntries, $list;
+ $offset = $actionListOffset{$offset};
+ }
+ }
+ $entries->[$_] = [ $nextState, $flags, $offset ];
+ }
+ my $entryTable = length($dat);
+ my $ligActionLists = ($entryTable + @$entries * 4 + 3) & ~3;
+ foreach (@$entries) {
+ $_->[2] += $ligActionLists if defined $_->[2];
+ $dat .= pack("nn", $_->[0], $_->[1] + $_->[2]);
+ }
+ $dat .= pack("C*", (0) x ($ligActionLists - $entryTable - @$entries * 4));
+
+ die "internal error" unless length($dat) == $ligActionLists;
+
+ my $componentTable = length($dat) + $actionListDataLength;
+ my $actionList;
+ foreach $actionList (@actionListEntries) {
+ foreach (0 .. $#$actionList) {
+ my $action = $actionList->[$_];
+ my $val = $action->{'component'} + $componentTable / 2;
+ $val += 0x40000000 if $val < 0;
+ $val &= 0x3fffffff;
+ $val |= 0x40000000 if $action->{'store'};
+ $val |= 0x80000000 if $_ == $#$actionList;
+ $dat .= pack("N", $val);
+ }
+ }
+
+ die "internal error" unless length($dat) == $componentTable;
+
+ my $components = $self->{'components'};
+ my $ligatureTable = $componentTable + @$components * 2;
+ $dat .= pack("n*", map { (index($_, '+') >= 0 ? $ligatureTable : 0) + $_ } @$components);
+
+ my $ligatures = $self->{'ligatures'};
+ $dat .= pack("n*", @$ligatures);
+
+ $dat1 = pack("nnnnnnn", $stateSize, $classTable, $stateArray, $entryTable, $ligActionLists, $componentTable, $ligatureTable);
+ substr($dat, 0, length($dat1)) = $dat1;
+
+ return $dat;
+}
+
+=head2 $t->print($fh)
+
+Prints a human-readable representation of the table
+
+=cut
+
+sub print
+{
+ my ($self, $fh) = @_;
+
+ my $post = $self->post();
+
+ $fh = 'STDOUT' unless defined $fh;
+
+ $self->print_classes($fh);
+
+ $fh->print("\n");
+ my $states = $self->{'states'};
+ foreach (0 .. $#$states) {
+ $fh->printf("\t\tState %d:", $_);
+ my $state = $states->[$_];
+ foreach (@$state) {
+ my $flags;
+ $flags .= "!" if ($_->{'flags'} & 0x4000);
+ $flags .= "*" if ($_->{'flags'} & 0x8000);
+ $fh->printf("\t(%s%d,%s)", $flags, $_->{'nextState'}, defined $_->{'actions'} ? $_->{'actions'} : "=");
+ }
+ $fh->print("\n");
+ }
+
+ $fh->print("\n");
+ my $actionLists = $self->{'actionLists'};
+ foreach (0 .. $#$actionLists) {
+ $fh->printf("\t\tList %d:\t", $_);
+ my $actionList = $actionLists->[$_];
+ $fh->printf("%s\n", join(", ", map { ($_->{'component'} . ($_->{'store'} ? "*" : "") ) } @$actionList));
+ }
+
+ my $ligatureTable = $self->{'ligatureTable'};
+
+ $fh->print("\n");
+ my $components = $self->{'components'};
+ foreach (0 .. $#$components) {
+ $fh->printf("\t\tComponent %d: %s\n", $_, $components->[$_]);
+ }
+
+ $fh->print("\n");
+ my $ligatures = $self->{'ligatures'};
+ foreach (0 .. $#$ligatures) {
+ $fh->printf("\t\tLigature %d: %d [%s]\n", $_, $ligatures->[$_], $post->{'VAL'}[$ligatures->[$_]]);
+ }
+}
+
+1;
+
+=head1 BUGS
+
+None known
+
+=head1 AUTHOR
+
+Jonathan Kew L<Jonathan_Kew at sil.org>. See L<Font::TTF::Font> for copyright and
+licensing.
+
+=cut
+
Modified: packages/libfont-ttf-perl/trunk/lib/Font/TTF/Mort/Noncontextual.pm
===================================================================
--- packages/libfont-ttf-perl/trunk/lib/Font/TTF/Mort/Noncontextual.pm 2006-01-17 02:56:43 UTC (rev 1966)
+++ packages/libfont-ttf-perl/trunk/lib/Font/TTF/Mort/Noncontextual.pm 2006-01-17 03:07:20 UTC (rev 1967)
@@ -1,95 +1,95 @@
-package Font::TTF::Mort::Noncontextual;
-
-=head1 NAME
-
-Font::TTF::Mort::Noncontextual
-
-=head1 METHODS
-
-=cut
-
-use strict;
-use vars qw(@ISA);
-use Font::TTF::Utils;
-use Font::TTF::AATutils;
-
- at ISA = qw(Font::TTF::Mort::Subtable);
-
-sub new
-{
- my ($class, $direction, $orientation, $subFeatureFlags) = @_;
- my ($self) = {
- 'direction' => $direction,
- 'orientation' => $orientation,
- 'subFeatureFlags' => $subFeatureFlags
- };
-
- $class = ref($class) || $class;
- bless $self, $class;
-}
-
-=head2 $t->read
-
-Reads the table into memory
-
-=cut
-
-sub read
-{
- my ($self, $fh) = @_;
- my ($dat);
-
- my ($format, $lookup) = AAT_read_lookup($fh, 2, $self->{'length'} - 8, undef);
- $self->{'format'} = $format;
- $self->{'lookup'} = $lookup;
-
- $self;
-}
-
-=head2 $t->pack_sub($fh)
-
-=cut
-
-sub pack_sub
-{
- my ($self) = @_;
-
- return AAT_pack_lookup($self->{'format'}, $self->{'lookup'}, 2, undef);
-}
-
-=head2 $t->print($fh)
-
-Prints a human-readable representation of the table
-
-=cut
-
-sub print
-{
- my ($self, $fh) = @_;
-
- my $post = $self->post();
-
- $fh = 'STDOUT' unless defined $fh;
-
- my $lookup = $self->{'lookup'};
- $fh->printf("\t\tLookup format %d\n", $self->{'format'});
- if (defined $lookup) {
- foreach (sort { $a <=> $b } keys %$lookup) {
- $fh->printf("\t\t\t%d [%s] -> %d [%s])\n", $_, $post->{'VAL'}[$_], $lookup->{$_}, $post->{'VAL'}[$lookup->{$_}]);
- }
- }
-}
-
-1;
-
-=head1 BUGS
-
-None known
-
-=head1 AUTHOR
-
-Jonathan Kew L<Jonathan_Kew at sil.org>. See L<Font::TTF::Font> for copyright and
-licensing.
-
-=cut
-
+package Font::TTF::Mort::Noncontextual;
+
+=head1 NAME
+
+Font::TTF::Mort::Noncontextual
+
+=head1 METHODS
+
+=cut
+
+use strict;
+use vars qw(@ISA);
+use Font::TTF::Utils;
+use Font::TTF::AATutils;
+
+ at ISA = qw(Font::TTF::Mort::Subtable);
+
+sub new
+{
+ my ($class, $direction, $orientation, $subFeatureFlags) = @_;
+ my ($self) = {
+ 'direction' => $direction,
+ 'orientation' => $orientation,
+ 'subFeatureFlags' => $subFeatureFlags
+ };
+
+ $class = ref($class) || $class;
+ bless $self, $class;
+}
+
+=head2 $t->read
+
+Reads the table into memory
+
+=cut
+
+sub read
+{
+ my ($self, $fh) = @_;
+ my ($dat);
+
+ my ($format, $lookup) = AAT_read_lookup($fh, 2, $self->{'length'} - 8, undef);
+ $self->{'format'} = $format;
+ $self->{'lookup'} = $lookup;
+
+ $self;
+}
+
+=head2 $t->pack_sub($fh)
+
+=cut
+
+sub pack_sub
+{
+ my ($self) = @_;
+
+ return AAT_pack_lookup($self->{'format'}, $self->{'lookup'}, 2, undef);
+}
+
+=head2 $t->print($fh)
+
+Prints a human-readable representation of the table
+
+=cut
+
+sub print
+{
+ my ($self, $fh) = @_;
+
+ my $post = $self->post();
+
+ $fh = 'STDOUT' unless defined $fh;
+
+ my $lookup = $self->{'lookup'};
+ $fh->printf("\t\tLookup format %d\n", $self->{'format'});
+ if (defined $lookup) {
+ foreach (sort { $a <=> $b } keys %$lookup) {
+ $fh->printf("\t\t\t%d [%s] -> %d [%s])\n", $_, $post->{'VAL'}[$_], $lookup->{$_}, $post->{'VAL'}[$lookup->{$_}]);
+ }
+ }
+}
+
+1;
+
+=head1 BUGS
+
+None known
+
+=head1 AUTHOR
+
+Jonathan Kew L<Jonathan_Kew at sil.org>. See L<Font::TTF::Font> for copyright and
+licensing.
+
+=cut
+
Modified: packages/libfont-ttf-perl/trunk/lib/Font/TTF/Mort/Rearrangement.pm
===================================================================
--- packages/libfont-ttf-perl/trunk/lib/Font/TTF/Mort/Rearrangement.pm 2006-01-17 02:56:43 UTC (rev 1966)
+++ packages/libfont-ttf-perl/trunk/lib/Font/TTF/Mort/Rearrangement.pm 2006-01-17 03:07:20 UTC (rev 1967)
@@ -1,107 +1,107 @@
-package Font::TTF::Mort::Rearrangement;
-
-=head1 NAME
-
-Font::TTF::Mort::Rearrangement
-
-=head1 METHODS
-
-=cut
-
-use strict;
-use vars qw(@ISA);
-use Font::TTF::Utils;
-use Font::TTF::AATutils;
-
- at ISA = qw(Font::TTF::Mort::Subtable);
-
-sub new
-{
- my ($class, $direction, $orientation, $subFeatureFlags) = @_;
- my ($self) = {
- 'direction' => $direction,
- 'orientation' => $orientation,
- 'subFeatureFlags' => $subFeatureFlags
- };
-
- $class = ref($class) || $class;
- bless $self, $class;
-}
-
-=head2 $t->read
-
-Reads the table into memory
-
-=cut
-
-sub read
-{
- my ($self, $fh) = @_;
-
- my ($classes, $states) = AAT_read_state_table($fh, 0);
- $self->{'classes'} = $classes;
- $self->{'states'} = $states;
-
- $self;
-}
-
-=head2 $t->pack_sub()
-
-=cut
-
-sub pack_sub
-{
- my ($self) = @_;
-
- return AAT_pack_state_table($self->{'classes'}, $self->{'states'}, 0);
-}
-
-=head2 $t->print($fh)
-
-Prints a human-readable representation of the table
-
-=cut
-
-sub print
-{
- my ($self, $fh) = @_;
-
- my $post = $self->post();
-
- $fh = 'STDOUT' unless defined $fh;
-
- $self->print_classes($fh);
-
- $fh->print("\n");
- my $states = $self->{'states'};
- my @verbs = ( "0", "Ax->xA", "xD->Dx", "AxD->DxA",
- "ABx->xAB", "ABx->xBA", "xCD->CDx", "xCD->DCx",
- "AxCD->CDxA", "AxCD->DCxA", "ABxD->DxAB", "ABxD->DxBA",
- "ABxCD->CDxAB", "ABxCD->CDxBA", "ABxCD->DCxAB", "ABxCD->DCxBA");
- foreach (0 .. $#$states) {
- $fh->printf("\t\tState %d:", $_);
- my $state = $states->[$_];
- foreach (@$state) {
- my $flags;
- $flags .= "!" if ($_->{'flags'} & 0x4000);
- $flags .= "<" if ($_->{'flags'} & 0x8000);
- $flags .= ">" if ($_->{'flags'} & 0x2000);
- $fh->printf("\t(%s%d,%s)", $flags, $_->{'nextState'}, $verbs[($_->{'flags'} & 0x000f)]);
- }
- $fh->print("\n");
- }
-}
-
-1;
-
-=head1 BUGS
-
-None known
-
-=head1 AUTHOR
-
-Jonathan Kew L<Jonathan_Kew at sil.org>. See L<Font::TTF::Font> for copyright and
-licensing.
-
-=cut
-
+package Font::TTF::Mort::Rearrangement;
+
+=head1 NAME
+
+Font::TTF::Mort::Rearrangement
+
+=head1 METHODS
+
+=cut
+
+use strict;
+use vars qw(@ISA);
+use Font::TTF::Utils;
+use Font::TTF::AATutils;
+
+ at ISA = qw(Font::TTF::Mort::Subtable);
+
+sub new
+{
+ my ($class, $direction, $orientation, $subFeatureFlags) = @_;
+ my ($self) = {
+ 'direction' => $direction,
+ 'orientation' => $orientation,
+ 'subFeatureFlags' => $subFeatureFlags
+ };
+
+ $class = ref($class) || $class;
+ bless $self, $class;
+}
+
+=head2 $t->read
+
+Reads the table into memory
+
+=cut
+
+sub read
+{
+ my ($self, $fh) = @_;
+
+ my ($classes, $states) = AAT_read_state_table($fh, 0);
+ $self->{'classes'} = $classes;
+ $self->{'states'} = $states;
+
+ $self;
+}
+
+=head2 $t->pack_sub()
+
+=cut
+
+sub pack_sub
+{
+ my ($self) = @_;
+
+ return AAT_pack_state_table($self->{'classes'}, $self->{'states'}, 0);
+}
+
+=head2 $t->print($fh)
+
+Prints a human-readable representation of the table
+
+=cut
+
+sub print
+{
+ my ($self, $fh) = @_;
+
+ my $post = $self->post();
+
+ $fh = 'STDOUT' unless defined $fh;
+
+ $self->print_classes($fh);
+
+ $fh->print("\n");
+ my $states = $self->{'states'};
+ my @verbs = ( "0", "Ax->xA", "xD->Dx", "AxD->DxA",
+ "ABx->xAB", "ABx->xBA", "xCD->CDx", "xCD->DCx",
+ "AxCD->CDxA", "AxCD->DCxA", "ABxD->DxAB", "ABxD->DxBA",
+ "ABxCD->CDxAB", "ABxCD->CDxBA", "ABxCD->DCxAB", "ABxCD->DCxBA");
+ foreach (0 .. $#$states) {
+ $fh->printf("\t\tState %d:", $_);
+ my $state = $states->[$_];
+ foreach (@$state) {
+ my $flags;
+ $flags .= "!" if ($_->{'flags'} & 0x4000);
+ $flags .= "<" if ($_->{'flags'} & 0x8000);
+ $flags .= ">" if ($_->{'flags'} & 0x2000);
+ $fh->printf("\t(%s%d,%s)", $flags, $_->{'nextState'}, $verbs[($_->{'flags'} & 0x000f)]);
+ }
+ $fh->print("\n");
+ }
+}
+
+1;
+
+=head1 BUGS
+
+None known
+
+=head1 AUTHOR
+
+Jonathan Kew L<Jonathan_Kew at sil.org>. See L<Font::TTF::Font> for copyright and
+licensing.
+
+=cut
+
Modified: packages/libfont-ttf-perl/trunk/lib/Font/TTF/Mort/Subtable.pm
===================================================================
--- packages/libfont-ttf-perl/trunk/lib/Font/TTF/Mort/Subtable.pm 2006-01-17 02:56:43 UTC (rev 1966)
+++ packages/libfont-ttf-perl/trunk/lib/Font/TTF/Mort/Subtable.pm 2006-01-17 03:07:20 UTC (rev 1967)
@@ -1,199 +1,200 @@
-package Font::TTF::Mort::Subtable;
-
-=head1 NAME
-
-Font::TTF::Mort::Subtable
-
-=head1 METHODS
-
-=cut
-
-use strict;
-use Font::TTF::Utils;
-use Font::TTF::AATutils;
-
-require Font::TTF::Mort::Rearrangement;
-require Font::TTF::Mort::Contextual;
-require Font::TTF::Mort::Ligature;
-require Font::TTF::Mort::Noncontextual;
-require Font::TTF::Mort::Insertion;
-
-sub new
-{
- my ($class) = @_;
- my ($self) = {};
-
- $class = ref($class) || $class;
-
- bless $self, $class;
-}
-
-sub create
-{
- my ($class, $type, $coverage, $subFeatureFlags, $length) = @_;
-
- $class = ref($class) || $class;
-
- my $subclass;
- if ($type == 0) {
- $subclass = 'Font::TTF::Mort::Rearrangement';
- }
- elsif ($type == 1) {
- $subclass = 'Font::TTF::Mort::Contextual';
- }
- elsif ($type == 2) {
- $subclass = 'Font::TTF::Mort::Ligature';
- }
- elsif ($type == 4) {
- $subclass = 'Font::TTF::Mort::Noncontextual';
- }
- elsif ($type == 5) {
- $subclass = 'Font::TTF::Mort::Insertion';
- }
-
- my ($self) = $subclass->new(
- (($coverage & 0x4000) ? 'RL' : 'LR'),
- (($coverage & 0x2000) ? 'VH' : ($coverage & 0x8000) ? 'V' : 'H'),
- $subFeatureFlags
- );
-
- $self->{'type'} = $type;
- $self->{'length'} = $length;
-
- $self;
-}
-
-=head2 $t->out($fh)
-
-Writes the table to a file
-
-=cut
-
-sub out
-{
- my ($self, $fh) = @_;
-
- my ($subtableStart) = $fh->tell();
- my ($type) = $self->{'type'};
- my ($coverage) = $type;
- $coverage += 0x4000 if $self->{'direction'} eq 'RL';
- $coverage += 0x2000 if $self->{'orientation'} eq 'VH';
- $coverage += 0x8000 if $self->{'orientation'} eq 'V';
-
- $fh->print(TTF_Pack("SSL", 0, $coverage, $self->{'subFeatureFlags'})); # placeholder for length
-
- my ($dat) = $self->pack_sub();
- $fh->print($dat);
-
- my ($length) = $fh->tell() - $subtableStart;
- my ($padBytes) = (4 - ($length & 3)) & 3;
- $fh->print(pack("C*", (0) x $padBytes));
- $length += $padBytes;
- $fh->seek($subtableStart, IO::File::SEEK_SET);
- $fh->print(pack("n", $length));
- $fh->seek($subtableStart + $length, IO::File::SEEK_SET);
-}
-
-=head2 $t->print($fh)
-
-Prints a human-readable representation of the table
-
-=cut
-
-sub post
-{
- my ($self) = @_;
-
- my ($post) = $self->{' PARENT'}{' PARENT'}{' PARENT'}{'post'};
- if (defined $post) {
- $post->read;
- }
- else {
- $post = {};
- }
-
- return $post;
-}
-
-sub feat
-{
- my ($self) = @_;
-
- return $self->{' PARENT'}->feat();
-}
-
-sub print
-{
- my ($self, $fh) = @_;
-
- my ($feat) = $self->feat();
- my ($post) = $self->post();
-
- $fh = 'STDOUT' unless defined $fh;
-
- my ($type) = $self->{'type'};
- my ($subFeatureFlags) = $self->{'subFeatureFlags'};
- my ($defaultFlags) = $self->{' PARENT'}{'defaultFlags'};
- my ($featureEntries) = $self->{' PARENT'}{'featureEntries'};
- $fh->printf("\n\t%s table, %s, %s, subFeatureFlags = %08x # %s (%s)\n",
- subtable_type_($type), $_->{'direction'}, $_->{'orientation'}, $subFeatureFlags,
- "Default " . ((($subFeatureFlags & $defaultFlags) != 0) ? "On" : "Off"),
- join(", ",
- map {
- join(": ", $feat->settingName($_->{'type'}, $_->{'setting'}) )
- } grep { ($_->{'enable'} & $subFeatureFlags) != 0 } @$featureEntries
- ) );
-}
-
-sub subtable_type_
-{
- my ($val) = @_;
- my ($res);
-
- my (@types) = (
- 'Rearrangement',
- 'Contextual',
- 'Ligature',
- undef,
- 'Non-contextual',
- 'Insertion',
- );
- $res = $types[$val] or ('Undefined (' . $val . ')');
-
- $res;
-}
-
-=head2 $t->print_classes($fh)
-
-Prints a human-readable representation of the table
-
-=cut
-
-sub print_classes
-{
- my ($self, $fh) = @_;
-
- my ($post) = $self->post();
-
- my ($classes) = $self->{'classes'};
- foreach (0 .. $#$classes) {
- my $class = $classes->[$_];
- if (defined $class) {
- $fh->printf("\t\tClass %d:\t%s\n", $_, join(", ", map { $_ . " [" . $post->{'VAL'}[$_] . "]" } @$class));
- }
- }
-}
-
-1;
-
-=head1 BUGS
-
-None known
-
-=head1 AUTHOR
-
-Jonathan Kew L<Jonathan_Kew at sil.org>. See L<Font::TTF::Font> for copyright and
-licensing.
-
-=cut
-
+package Font::TTF::Mort::Subtable;
+
+=head1 NAME
+
+Font::TTF::Mort::Subtable
+
+=head1 METHODS
+
+=cut
+
+use strict;
+use Font::TTF::Utils;
+use Font::TTF::AATutils;
+use IO::File;
+
+require Font::TTF::Mort::Rearrangement;
+require Font::TTF::Mort::Contextual;
+require Font::TTF::Mort::Ligature;
+require Font::TTF::Mort::Noncontextual;
+require Font::TTF::Mort::Insertion;
+
+sub new
+{
+ my ($class) = @_;
+ my ($self) = {};
+
+ $class = ref($class) || $class;
+
+ bless $self, $class;
+}
+
+sub create
+{
+ my ($class, $type, $coverage, $subFeatureFlags, $length) = @_;
+
+ $class = ref($class) || $class;
+
+ my $subclass;
+ if ($type == 0) {
+ $subclass = 'Font::TTF::Mort::Rearrangement';
+ }
+ elsif ($type == 1) {
+ $subclass = 'Font::TTF::Mort::Contextual';
+ }
+ elsif ($type == 2) {
+ $subclass = 'Font::TTF::Mort::Ligature';
+ }
+ elsif ($type == 4) {
+ $subclass = 'Font::TTF::Mort::Noncontextual';
+ }
+ elsif ($type == 5) {
+ $subclass = 'Font::TTF::Mort::Insertion';
+ }
+
+ my ($self) = $subclass->new(
+ (($coverage & 0x4000) ? 'RL' : 'LR'),
+ (($coverage & 0x2000) ? 'VH' : ($coverage & 0x8000) ? 'V' : 'H'),
+ $subFeatureFlags
+ );
+
+ $self->{'type'} = $type;
+ $self->{'length'} = $length;
+
+ $self;
+}
+
+=head2 $t->out($fh)
+
+Writes the table to a file
+
+=cut
+
+sub out
+{
+ my ($self, $fh) = @_;
+
+ my ($subtableStart) = $fh->tell();
+ my ($type) = $self->{'type'};
+ my ($coverage) = $type;
+ $coverage += 0x4000 if $self->{'direction'} eq 'RL';
+ $coverage += 0x2000 if $self->{'orientation'} eq 'VH';
+ $coverage += 0x8000 if $self->{'orientation'} eq 'V';
+
+ $fh->print(TTF_Pack("SSL", 0, $coverage, $self->{'subFeatureFlags'})); # placeholder for length
+
+ my ($dat) = $self->pack_sub();
+ $fh->print($dat);
+
+ my ($length) = $fh->tell() - $subtableStart;
+ my ($padBytes) = (4 - ($length & 3)) & 3;
+ $fh->print(pack("C*", (0) x $padBytes));
+ $length += $padBytes;
+ $fh->seek($subtableStart, IO::File::SEEK_SET);
+ $fh->print(pack("n", $length));
+ $fh->seek($subtableStart + $length, IO::File::SEEK_SET);
+}
+
+=head2 $t->print($fh)
+
+Prints a human-readable representation of the table
+
+=cut
+
+sub post
+{
+ my ($self) = @_;
+
+ my ($post) = $self->{' PARENT'}{' PARENT'}{' PARENT'}{'post'};
+ if (defined $post) {
+ $post->read;
+ }
+ else {
+ $post = {};
+ }
+
+ return $post;
+}
+
+sub feat
+{
+ my ($self) = @_;
+
+ return $self->{' PARENT'}->feat();
+}
+
+sub print
+{
+ my ($self, $fh) = @_;
+
+ my ($feat) = $self->feat();
+ my ($post) = $self->post();
+
+ $fh = 'STDOUT' unless defined $fh;
+
+ my ($type) = $self->{'type'};
+ my ($subFeatureFlags) = $self->{'subFeatureFlags'};
+ my ($defaultFlags) = $self->{' PARENT'}{'defaultFlags'};
+ my ($featureEntries) = $self->{' PARENT'}{'featureEntries'};
+ $fh->printf("\n\t%s table, %s, %s, subFeatureFlags = %08x # %s (%s)\n",
+ subtable_type_($type), $_->{'direction'}, $_->{'orientation'}, $subFeatureFlags,
+ "Default " . ((($subFeatureFlags & $defaultFlags) != 0) ? "On" : "Off"),
+ join(", ",
+ map {
+ join(": ", $feat->settingName($_->{'type'}, $_->{'setting'}) )
+ } grep { ($_->{'enable'} & $subFeatureFlags) != 0 } @$featureEntries
+ ) );
+}
+
+sub subtable_type_
+{
+ my ($val) = @_;
+ my ($res);
+
+ my (@types) = (
+ 'Rearrangement',
+ 'Contextual',
+ 'Ligature',
+ undef,
+ 'Non-contextual',
+ 'Insertion',
+ );
+ $res = $types[$val] or ('Undefined (' . $val . ')');
+
+ $res;
+}
+
+=head2 $t->print_classes($fh)
+
+Prints a human-readable representation of the table
+
+=cut
+
+sub print_classes
+{
+ my ($self, $fh) = @_;
+
+ my ($post) = $self->post();
+
+ my ($classes) = $self->{'classes'};
+ foreach (0 .. $#$classes) {
+ my $class = $classes->[$_];
+ if (defined $class) {
+ $fh->printf("\t\tClass %d:\t%s\n", $_, join(", ", map { $_ . " [" . $post->{'VAL'}[$_] . "]" } @$class));
+ }
+ }
+}
+
+1;
+
+=head1 BUGS
+
+None known
+
+=head1 AUTHOR
+
+Jonathan Kew L<Jonathan_Kew at sil.org>. See L<Font::TTF::Font> for copyright and
+licensing.
+
+=cut
+
Modified: packages/libfont-ttf-perl/trunk/lib/Font/TTF/Mort.pm
===================================================================
--- packages/libfont-ttf-perl/trunk/lib/Font/TTF/Mort.pm 2006-01-17 02:56:43 UTC (rev 1966)
+++ packages/libfont-ttf-perl/trunk/lib/Font/TTF/Mort.pm 2006-01-17 03:07:20 UTC (rev 1967)
@@ -1,108 +1,108 @@
-package Font::TTF::Mort;
-
-=head1 NAME
-
-Font::TTF::Mort - Glyph Metamorphosis table in a font
-
-=head1 METHODS
-
-=cut
-
-use strict;
-use vars qw(@ISA);
-use Font::TTF::Utils;
-use Font::TTF::AATutils;
-use Font::TTF::Mort::Chain;
-
- at ISA = qw(Font::TTF::Table);
-
-=head2 $t->read
-
-Reads the table into memory
-
-=cut
-
-sub read
-{
- my ($self) = @_;
- my ($dat, $fh, $numChains);
-
- $self->SUPER::read or return $self;
-
- $fh = $self->{' INFILE'};
-
- $fh->read($dat, 8);
- ($self->{'version'}, $numChains) = TTF_Unpack("fL", $dat);
-
- my $chains = [];
- foreach (1 .. $numChains) {
- my $chain = new Font::TTF::Mort::Chain->new;
- $chain->read($fh);
- $chain->{' PARENT'} = $self;
- push @$chains, $chain;
- }
-
- $self->{'chains'} = $chains;
-
- $self;
-}
-
-=head2 $t->out($fh)
-
-Writes the table to a file either from memory or by copying
-
-=cut
-
-sub out
-{
- my ($self, $fh) = @_;
-
- return $self->SUPER::out($fh) unless $self->{' read'};
-
- my $chains = $self->{'chains'};
- $fh->print(TTF_Pack("fL", $self->{'version'}, scalar @$chains));
-
- foreach (@$chains) {
- $_->out($fh);
- }
-}
-
-=head2 $t->print($fh)
-
-Prints a human-readable representation of the table
-
-=cut
-
-sub print
-{
- my ($self, $fh) = @_;
-
- $self->read unless $self->{' read'};
- my $feat = $self->{' PARENT'}->{'feat'};
- $feat->read;
- my $post = $self->{' PARENT'}->{'post'};
- $post->read;
-
- $fh = 'STDOUT' unless defined $fh;
-
- $fh->printf("version %f\n", $self->{'version'});
-
- my $chains = $self->{'chains'};
- foreach (@$chains) {
- $_->print($fh);
- }
-}
-
-1;
-
-=head1 BUGS
-
-None known
-
-=head1 AUTHOR
-
-Jonathan Kew L<Jonathan_Kew at sil.org>. See L<Font::TTF::Font> for copyright and
-licensing.
-
-=cut
-
+package Font::TTF::Mort;
+
+=head1 NAME
+
+Font::TTF::Mort - Glyph Metamorphosis table in a font
+
+=head1 METHODS
+
+=cut
+
+use strict;
+use vars qw(@ISA);
+use Font::TTF::Utils;
+use Font::TTF::AATutils;
+use Font::TTF::Mort::Chain;
+
+ at ISA = qw(Font::TTF::Table);
+
+=head2 $t->read
+
+Reads the table into memory
+
+=cut
+
+sub read
+{
+ my ($self) = @_;
+ my ($dat, $fh, $numChains);
+
+ $self->SUPER::read or return $self;
+
+ $fh = $self->{' INFILE'};
+
+ $fh->read($dat, 8);
+ ($self->{'version'}, $numChains) = TTF_Unpack("fL", $dat);
+
+ my $chains = [];
+ foreach (1 .. $numChains) {
+ my $chain = new Font::TTF::Mort::Chain->new;
+ $chain->read($fh);
+ $chain->{' PARENT'} = $self;
+ push @$chains, $chain;
+ }
+
+ $self->{'chains'} = $chains;
+
+ $self;
+}
+
+=head2 $t->out($fh)
+
+Writes the table to a file either from memory or by copying
+
+=cut
+
+sub out
+{
+ my ($self, $fh) = @_;
+
+ return $self->SUPER::out($fh) unless $self->{' read'};
+
+ my $chains = $self->{'chains'};
+ $fh->print(TTF_Pack("fL", $self->{'version'}, scalar @$chains));
+
+ foreach (@$chains) {
+ $_->out($fh);
+ }
+}
+
+=head2 $t->print($fh)
+
+Prints a human-readable representation of the table
+
+=cut
+
+sub print
+{
+ my ($self, $fh) = @_;
+
+ $self->read unless $self->{' read'};
+ my $feat = $self->{' PARENT'}->{'feat'};
+ $feat->read;
+ my $post = $self->{' PARENT'}->{'post'};
+ $post->read;
+
+ $fh = 'STDOUT' unless defined $fh;
+
+ $fh->printf("version %f\n", $self->{'version'});
+
+ my $chains = $self->{'chains'};
+ foreach (@$chains) {
+ $_->print($fh);
+ }
+}
+
+1;
+
+=head1 BUGS
+
+None known
+
+=head1 AUTHOR
+
+Jonathan Kew L<Jonathan_Kew at sil.org>. See L<Font::TTF::Font> for copyright and
+licensing.
+
+=cut
+
Modified: packages/libfont-ttf-perl/trunk/lib/Font/TTF/Name.pm
===================================================================
--- packages/libfont-ttf-perl/trunk/lib/Font/TTF/Name.pm 2006-01-17 02:56:43 UTC (rev 1966)
+++ packages/libfont-ttf-perl/trunk/lib/Font/TTF/Name.pm 2006-01-17 03:07:20 UTC (rev 1967)
@@ -1,472 +1,473 @@
-package Font::TTF::Name;
-
-=head1 NAME
-
-Font::TTF::Name - String table for a TTF font
-
-=head1 DESCRIPTION
-
-Strings are held by number, platform, encoding and language. Strings are
-accessed as:
-
- $f->{'name'}{'strings'}[$number][$platform_id][$encoding_id]{$language_id}
-
-Notice that the language is held in an associative array due to its sparse
-nature on some platforms such as Microsoft ($pid = 3). Notice also that the
-array order is different from the stored array order (platform, encoding,
-language, number) to allow for easy manipulation of strings by number (which is
-what I guess most people will want to do).
-
-By default, C<$Font::TTF::Name::utf8> is set to 1, and strings will be stored as UTF8 wherever
-possible. The method C<is_utf8> can be used to find out if a string in a particular
-platform and encoding will be returned as UTF8. Unicode strings are always
-converted if utf8 is requested. Otherwise, strings are stored according to platform:
-
- ***WARNING NON-UTF8 is deprecated and utf8 strings has become the default***
-
-You now have to set <$Font::TTF::Name::utf8> to 0 to get the old behaviour.
-
-=over 4
-
-=item Apple Unicode (platform id = 0)
-
-Data is stored as network ordered UCS2. There is no encoding id for this platform
-but there are language ids as per Mac language ids.
-
-=item Mac (platform id = 1)
-
-Data is stored as 8-bit binary data, leaving the interpretation to the user
-according to encoding id.
-
-=item Unicode (platform id = 2)
-
-Currently stored as 16-bit network ordered UCS2. Upon release of Perl 5.005 this
-will change to utf8 assuming current UCS2 semantics for all encoding ids.
-
-=item Windows (platform id = 3)
-
-As per Unicode, the data is currently stored as 16-bit network ordered UCS2. Upon
-release of Perl 5.005 this will change to utf8 assuming current UCS2 semantics for
-all encoding ids.
-
-=back
-
-=head1 INSTANCE VARIABLES
-
-=over 4
-
-=item strings
-
-An array of arrays, etc.
-
-=back
-
-=head1 METHODS
-
-=cut
-
-use strict;
-use vars qw(@ISA $VERSION @apple_encs @apple_encodings $utf8 $cp_1252 @cp_1252);
-use Font::TTF::Table;
-use Font::TTF::Utils;
- at ISA = qw(Font::TTF::Table);
-
-$utf8 = 1;
-
-{
- my ($count, $i);
- eval {require Compress::Zlib;};
- unless ($@)
- {
- for ($i = 0; $i <= $#apple_encs; $i++)
- {
- $apple_encodings[0][$i] = [unpack("n*", Compress::Zlib::uncompress(unpack("u", $apple_encs[$i])))]
- if (defined $apple_encs[$i]);
- $count = 0;
- $apple_encodings[1][$i] = {map({$_ => $count++} @{$apple_encodings[0][$i]})};
- }
- $cp_1252[0] = [unpack("n*", Compress::Zlib::uncompress(unpack("u", $cp_1252)))];
- $count = 0;
- $cp_1252[1] = {map({$_ => $count++} @{$cp_1252[0]})};
- }
-}
-
-
-$VERSION = 1.1; # MJPH 17-JUN-2000 Add utf8 support
-# $VERSION = 1.001; # MJPH 10-AUG-1998 Put $number first in list
-
-=head2 $t->read
-
-Reads all the names into memory
-
-=cut
-
-sub read
-{
- my ($self) = @_;
- my ($fh) = $self->{' INFILE'};
- my ($dat, $num, $stroff, $i, $pid, $eid, $lid, $nid, $len, $off, $here);
-
- $self->SUPER::read or return $self;
- $fh->read($dat, 6);
- ($num, $stroff) = unpack("x2nn", $dat);
- for ($i = 0; $i < $num; $i++)
- {
- $fh->read($dat, 12);
- ($pid, $eid, $lid, $nid, $len, $off) = unpack("n6", $dat);
- $here = $fh->tell();
- $fh->seek($self->{' OFFSET'} + $stroff + $off, 0);
- $fh->read($dat, $len);
- if ($utf8)
- {
- if ($pid == 1 && defined $apple_encodings[0][$eid])
- { $dat = TTF_word_utf8(pack("n*", map({$apple_encodings[0][$eid][$_]} unpack("C*", $dat)))); }
- elsif ($pid == 2 && $eid == 2 && defined @cp_1252)
- { $dat = TTF_word_utf8(pack("n*", map({$cp_1252[0][$_]} unpack("C*", $dat)))); }
- elsif ($pid == 0 || $pid == 3 || ($pid == 2 && $eid == 1))
- { $dat = TTF_word_utf8($dat); }
- }
- $self->{'strings'}[$nid][$pid][$eid]{$lid} = $dat;
- $fh->seek($here, 0);
- }
- $self;
-}
-
-
-=head2 $t->out($fh)
-
-Writes out all the strings
-
-=cut
-
-sub out
-{
- my ($self, $fh) = @_;
- my ($pid, $eid, $lid, $nid, $todo, @todo);
- my ($len, $offset, $loc, $stroff, $endloc, $str_trans);
-
- return $self->SUPER::out($fh) unless $self->{' read'};
-
- $loc = $fh->tell();
- $fh->print(pack("n3", 0, 0, 0));
- foreach $nid (0 .. $#{$self->{'strings'}})
- {
- foreach $pid (0 .. $#{$self->{'strings'}[$nid]})
- {
- foreach $eid (0 .. $#{$self->{'strings'}[$nid][$pid]})
- {
- foreach $lid (sort keys %{$self->{'strings'}[$nid][$pid][$eid]})
- {
- $str_trans = $self->{'strings'}[$nid][$pid][$eid]{$lid};
- if ($utf8)
- {
- if ($pid == 1 && defined $apple_encodings[1][$eid])
- { $str_trans = pack("C*",
- map({$apple_encodings[1][$eid]{$_} || "?"} unpack("n*",
- TTF_utf8_word($str_trans)))); }
- elsif ($pid == 2 && $eid == 2 && defined @cp_1252)
- { $str_trans = pack("C*",
- map({$cp_1252[1][$eid]{$_} || "?"} unpack("n*",
- TTF_utf8_word($str_trans)))); }
- elsif ($pid == 2 && $eid == 0)
- { $str_trans =~ s/[\xc0-\xff][\x80-\xbf]+/?/og; }
- elsif ($pid == 0 || $pid == 3 || ($pid == 2 && $eid == 1))
- { $str_trans = TTF_utf8_word($str_trans); }
- }
- push (@todo, [$pid, $eid, $lid, $nid, $str_trans]);
- }
- }
- }
- }
-
- $offset = 0;
- @todo = (sort {$a->[0] <=> $b->[0] || $a->[1] <=> $b->[1] || $a->[2] <=> $b->[2]
- || $a->[3] <=> $b->[3]} @todo);
- foreach $todo (@todo)
- {
- $len = length($todo->[4]);
- $fh->print(pack("n6", @{$todo}[0..3], $len, $offset));
- $offset += $len;
- }
-
- $stroff = $fh->tell() - $loc;
- foreach $todo (@todo)
- { $fh->print($todo->[4]); }
-
- $endloc = $fh->tell();
- $fh->seek($loc, 0);
- $fh->print(pack("n3", 0, $#todo + 1, $stroff));
- $fh->seek($endloc, 0);
- $self;
-}
-
-
-=head2 $t->XML_element($context, $depth, $key, $value)
-
-Outputs the string element in nice XML (which is all the table really!)
-
-=cut
-
-sub XML_element
-{
- my ($self) = shift;
- my ($context, $depth, $key, $value) = @_;
- my ($fh) = $context->{'fh'};
- my ($nid, $pid, $eid, $lid);
-
- return $self->SUPER::XML_element(@_) unless ($key eq 'strings');
-
- foreach $nid (0 .. $#{$self->{'strings'}})
- {
- next unless ref($self->{'strings'}[$nid]);
-# $fh->print("$depth<strings id='$nid'>\n");
- foreach $pid (0 .. $#{$self->{'strings'}[$nid]})
- {
- foreach $eid (0 .. $#{$self->{'strings'}[$nid][$pid]})
- {
- foreach $lid (sort {$a <=> $b} keys %{$self->{'strings'}[$nid][$pid][$eid]})
- {
- $fh->printf("%s<string id='%s' platform='%s' encoding='%s' language='%s'>\n%s%s%s\n%s</string>\n",
- $depth, $nid, $pid, $eid, $lid, $depth,
- $context->{'indent'}, $self->{'strings'}[$nid][$pid][$eid]{$lid}, $depth);
- }
- }
- }
-# $fh->print("$depth</strings>\n");
- }
- $self;
-}
-
-
-=head2 $t->XML_end($context, $tag, %attrs)
-
-Store strings in the right place
-
-=cut
-
-sub XML_end
-{
- my ($self) = shift;
- my ($context, $tag, %attrs) = @_;
-
- if ($tag eq 'string')
- {
- $self->{'strings'}[$attrs{'id'}][$attrs{'platform'}][$attrs{'encoding'}]{$attrs{'language'}}
- = $context->{'text'};
- return $context;
- }
- else
- { return $self->SUPER::XML_end(@_); }
-}
-
-=head2 is_utf8($pid, $eid)
-
-Returns whether a string of a given platform and encoding is going to be in UTF8
-
-=cut
-
-sub is_utf8
-{
- my ($self, $pid, $eid) = @_;
-
- return ($utf8 && ($pid == 0 || $pid == 3 || ($pid == 2 && ($eid != 2 || defined @cp_1252))
- || ($pid == 1 && defined $apple_encodings[$eid])));
-}
-
-
-=head2 find_name($nid)
-
-Hunts down a name in all the standard places and returns the string and for an
-array context the pid, eid & lid as well
-
-=cut
-
-sub find_name
-{
- my ($self, $nid) = @_;
- my ($res, $pid, $eid, $lid, $look, $k);
-
- my (@lookup) = ([3, 1, 1033], [3, 1, -1], [3, 0, 1033], [3, 0, -1], [2, 1, -1], [2, 2, -1], [2, 0, -1],
- [0, 0, 0], [1, 0, 0]);
- foreach $look (@lookup)
- {
- ($pid, $eid, $lid) = @$look;
- if ($lid == -1)
- {
- foreach $k (keys %{$self->{'strings'}[$nid][$pid][$eid]})
- {
- if (($res = $self->{strings}[$nid][$pid][$eid]{$k}) ne '')
- {
- $lid = $k;
- last;
- }
- }
- } else
- { $res = $self->{strings}[$nid][$pid][$eid]{$lid} }
- if ($res ne '')
- { return wantarray ? ($res, $pid, $eid, $lid) : $res; }
- }
- return '';
-}
-
-
-BEGIN {
- at apple_encs = (
-<<'EOT',
-M>)RES==NCW$`@.'G_S5Q*L(!#?+K1VO4:.W6IJA-:\^BM?>L>1&NP(A0Q$BL
-M<*!62ZV8Z1)[K]BE$MR#O,=/7OW]7T&*6"NMI4K31EOMM)>N at XXZZ2Q#IBZZ
-MZJ:['GKJ)4NVWOKHJ]\_/\!`@PR68XBAALDUW`@CC3+:&&.-,UZ>?!-,-,ED
-M4TPUS70SS#3+;`7FF&N>0D7F6V"A119;8JEEEEMAI5566V.M==;;H-A&FVRV
-MQ5;;_OTONJ3<%;?<5^NQ1YYXYJGG7GKME3?>>N^=#S[ZY(O/OOKNFU]^JO<[
-M!$?LLMO>$#OAH4-*4F+'[(L+E*F,6SH:%\9%]C@>1W&CN&%2:9QNO]-))5ZH
-M<]9.!^/DQ/8X-V[@@#,AS0ZE+KB7R$ODA\:A26@>6H2FH9D?J17^)(I#3C at 8
-MLD)V?:(^"BE.AN30,F0XK\(Y5UUVW0TW77/'W;H_;JM6HRJ1&95%M0Y'E5%5
-.5.U4]""JB<K_`B>`?E$`
-EOT
-
-undef,
-undef,
-undef,
-<<'EOT',
-M>)RES[=/%```1O$WO8G_@$'J';W70Z2WHS>5WJN%8D6%D;BZ,3*P,;#C2D(8
-M,9&)08V)+4*(1((X2'(#[.:;7[[\*./_%D,L<<230"(!@B213`JII)%.!IED
-MD4T.N>213P&%%%%,B!)N4LJMR[Z<"BJIHIH::JFCG@;"--)$,RVTTD8['732
-M13>WN<-=>NBECWX&&&2(848898QQ)IADBFEFF.4>]WG`0^:89X%%'O&8)SSE
-M&<]9X at 4O><4R*Y?_.ZRSRQ[[''#(1S[PB<]NL\D7OO&5[_S at 9TR`(XXYX1=O
-M.>4W9_SAG`O^7OF=O>XW*N)WV!%''7/<"2>=<MH90D9'_-X(AHTUSG at 33#1@
-MT"2333'5--/-,-,LL\TQUSSS+;#0(HL-7?DMM\)*JZRVQEKKK+?!L(TVV6R+
-9K;;9;H<K+KGJ>S?<\K5O(G[7?/</+>Y>'```
-EOT
-
-<<'EOT',
-M>)RED$LSEW$`A9_-^00L,H-^(=>4Y%^2J'1Q*Y+[I2(BHA`B?!%J6EM1*28S
-M;9II[/PI*7*_%TUN\_*VZ%W:FN9LSYEGGD,\_Q?#$?SP)X"C!!)$,"&$$L8Q
-MPCG."2(X222GB,+%:<X0S5EB.$<LYXES]A>XR"42N,P5KG*-1))()H54KG.#
-M--*Y20:WR"2+;'+()8]\"BBDB-O<X2[%E'"/4LJX3SD5/*"2*AY230V/>$PM
-M==3SA`8::>(IS;3PC%;::'?X'^W#?&(0-Z-,,,,TL\PSQP)+K+#,*C]9XQ?K
-M_.8/FVRPQ0[;[+&+S=_]_J;KX/Y6I?&U.JQ.Z[GU0 at -VBNTR@;Q4G]ZI5V_U
-MQG at 83^-M?,PAXV6'VF'ZH&Z]4H_>J]]IO=:0W!K6B#[KBT;U56/ZIN\:UX1^
-?:%)3FM:,9C6G>2UH44M:UHI6'?<BYX,"6O\!%-%\5```
-EOT
-
-<<'EOT',
-M>)RES5=OSG$`0.$CYR.(A(3DUS]J4WOO59O6;&F+UMY[7R&(V'N^4ETZ=*"J
-M:M:H=>E*0D1B)7HC1KC0[R#G^LEA,/]7((Z(EK2B-?&TH2WM:$\'.M*)SG0A
-M@:YTHSL]Z$DO>M.'OO2C/P,8R*`&/X2A#&,X(QC)*$:3R!C&,H[Q3&`BDYC,
-M%))(9BK3F,X,9C*+%%*9S1S22">#N<QC/IEDL8"%+&(Q2UC*,I:S at I6L8C5K
-M6,LZUK.!C6QB,UO8RC:VLZ/A7TL5Y=11P6O>N(MWO.>#.\GG(Y_YQ!>^DAT7
-M\8WZ$%$3$OC.#W(IYC=_^!N"1SWF*<]ZP1AO*:'`;*^0%V502J6'*8LRHRQR
-M/.)Q3WC2TY[QG+D6FF^!19ZGR(M>BA*]3"'5(9Z8.>:YVSV-DD/CT"0T#RU"
-MT]",G^YUG_L]8+$E7O6%!WUIF>4^]9K7?6R%E59YQUM6>]L:[WK/5][WH;7>
-4M,X'/O&1-WSF<P]9^BOV#YW%>_\`
-EOT
-
-<<'EOT',
-M>)RERT=.%5``0-&+7K'&!B(@X/L/^/3>ZZ?SZ=*K@`KVWOL:U!68.#!&8G2@
-M$Q?F5/=@SOB0XO\$$D2**:&4)&644T$E55130RUUU--`(TTTTT(K;;3302==
-M=--#[[_?1S\###+$,".,DF:,<2:89(II9KC`+'/,L\`B2RRSPBIKK+/!13;9
-M8IM+7.8*.^QRE6M<YP8WN<5M[G"7>]SG`0]YQ&.>\)1G/.<%+WG%:][PEI0G
-M/>5IL\SVC#F>-=<\\SUG at 846>=Y at PFBQ)9::M,QR*ZRTRFIKK+4N!+[[CD]\
-M#I%?9O*-+XGH/N?BMON=CT7\B#MQUR5^^MY#ZH('7?:PJQYQS14/L!?S,S[$
-M=,SD*[]#DH\>==UC;K at 8LD)V*`B%(3?D\2<4>=Q-3[B5R#'#66>LM\%&FVRV
-GQ5;;;+?#3KOLML=>4_;9[X"##CGLB*.F'7/<"2>=<CKL_06V`DD#
-EOT
-
-undef,
-<<'EOT',
-M>)RED-DVUG$`1;=:U*Y%0C)5O^^/SSS/F>>9#"$JE7D>"D6\3S=>Q^MPU^JF
-M&^M<G[7//G1ROP1B1.130"%QBBBFA%+***>"2JJHIH9:ZJBG at 4:::*:%M[32
-M1CL==_TNNNFAES[Z&6"0(889890QQIE at DG=,,<T,L[QGCGD6^,`B2WSD$Y]9
-MY at M?^<8*JZRQS@:;;+'-#KOLL<\!AQQQS'=^<,(I9_SD%^=<\)M+KN[X-U%:
-M2`\9(2MDAWB(^,-U+/KKYYJ'_W_`!!_XT$23?.1C]8E/3?&9J2:;9KH9/O>%
-MF;XTRVQSS#7/5[[VC<&8D?D66&C<(HLML=0RRZVPTBJ7K;;&6NNLM\%&FVRV
-L):388:===MMCKP,..F2_(XXZYK#CMKGZS[YU-]QTRVUWW'7/?0]N`4(?0WT`
-EOT
-
-<<'EOT',
-M>)RED,5.0U$415=(D.X!$"ANMX^VN+M#D>+N[H4"Q5W^APF_PZ\PY.9-"`-&
-MY.3LG>-"#_\3 at P^'8OP$"%)"*6644T$E55130RUUU--`(TTTTT(K;;3302==
-M=-OZ7OH(T<\`@PP19I at 11AECG`DFF6*:&6:98YX%%EEBF15666.=#3;98IL=
-M=MECGP,.B7#$,5%...6,&.=<<,D5U]QPRQWW//#($\^\\,J;G?_II)ETXS79
-M)L<$C<,['S[GYSY=?FWK6E>Z^?L'BK,:KP0E*DD>R?6E*-7E='DM9BA36<I6
-MCG*5IWP5J%!%,O+)4;'\"BBH$I7:S')5J%)5JE:-M6JMUKM]FM1LL55M)EG=
-GZE&O^A1R(V$-NSRF<8L3ZO3L_]KN4!$=Z5A1G>A49XKI_!M<9D8J
-EOT
-
-<<'EOT',
-M>)RED,E3SW$8QU_77@<''+A]^Y5(2-F7+"%92\B^ES5ES]H,)L(8&21E*UNH
-M&"8T8ZS3I(FS_T"$_`L^-^/D8)YY/^]Y/\L\"Y/Y/XN()T8"B0P at B8$,(IG!
-MI#"$H0PCE>&DD<X(1C**T8QA+.,8SP0FDL&DT#^%J60RC>G,((N99#.+V<QA
-M+O.83PZY+""/A2QB,?DL82G+6,X*5K**U:QA+>M8SP8**&0CF]C,%K:RC2*V
-M4TP).]C)+G:SA[WLHY3]'.`@ASC,$<K"_,^QWE&?J&_4+^H?)44Q[M,<'_MS
-M7USAOS[@48]YW')/>-(*3WG:,R%ZSDK/!K[@1<][R2HO6^T5:ZSUJM>\[@UO
-M6F>]M[SM'>]ZSX90_\"'-MIDLX^">ASPQ*?!M_C,Y[ZP->KE*U_[QK>^\WW(
-CM/O!ML"=?K3#3[Z,*_AKOR]V^=5O=OO='_ZTQU^_`2-%:*``
-EOT
-
-undef,
-undef,
-undef,
-undef,
-undef,
-undef,
-undef,
-undef,
-undef,
-<<'EOT',
-M>)REC]=.E&$`1(\%&W at 4004%_7:!I?>.Z-+[TJL*=K"`BH`*J,_"+2'A!7PW
-MX;\2[LG<3#*9G!F2G$V!&'$***2(!,644$H9Y5102175U%!+'?4TT$@3S;30
-M2AN/:.<Q3Z)^!YUTT4T/O?31SP"###',""E&&6.<"2:98IH99IECG at 6>\HSG
-M+++$"U[RBM>\X2WO6&:%]WS@(Y]898W/?.$KZWQC at TVV^,X/?K+-#KO\XC=_
-M(OX!?T/"`0<=<MB1$Q?R0KXIDB%NK?TVV&B3S:?RG)`;]?<\YWDO>-$T+WG9
-M*U[UFNEF>%V]X4TSO666V=[VCG?-,==[WC?/?!_XT&#,N`466F3"8DLLM<QR
-M*ZRTRFIK(GJ=]?_Y+;;:]N\HI(>LD&W2#COMLML>>^V+=IX\2<7BCCGNA)-.
-0.>V,L\XY[P*'[!\#D^='L@``
-EOT
-
-undef,
-undef,
-undef,
-undef,
-undef,
-undef,
-undef,
-undef,
-undef,
-);
-
-$cp_1252 = (
-<<'EOT',
-M>)P-SD-B'5```,#YJ6VE>DEM&[\VD]JVF?H./4'-U+93V[9M:SV;$141(Y74
-MTD at KG?0RR"B3S++(*IOL<L at IE]SRR"N?_`J(55`AA1515!`G7C'%E5!2*:65
-M458YY550426555%5-=754%,MM=515SWU-=!05".--=%4,\VUT%(KK;715COM
-M==!1)YTE2-1%5]UTUT-/O?361U_]]#?`0(,,-L10PPPWPDBCC#;&6..,-\%$
-MDTPVQ5333)=DAIEFF6V.N>:%9-$0&YD?BH22(82XF)10.3(@U(DDB$;F_/]%
-M0_Y0(!0*A4-\R!5RQ]R*BX\,#'4CB?]];B3)`@LMLM at 22RVSW`HKK;):LC76
-M6F>]#3;:9+,MMMIFNQUVVF6W/?;:9[\##CKDL"-2''7,<2><=,II9YQUSGD7
-M7'3)95=<=<UU-]QTRVUWW'7/?0\\],AC3SSUS',OO/3*:V^\]<Y['WSTR6=?
-1?/7-=S_\],MO?_S]!Y==>0@`
-EOT
-);
-}
-
-1;
-
-=head1 BUGS
-
-=over 4
-
-=item *
-
-Unicode type strings will be stored in utf8 for all known platforms,
-once Perl 5.6 has been released and I can find all the mapping tables, etc.
-
-=back
-
-=head1 AUTHOR
-
-Martin Hosken Martin_Hosken at sil.org. See L<Font::TTF::Font> for copyright and
-licensing.
-
-=cut
-
+package Font::TTF::Name;
+
+=head1 NAME
+
+Font::TTF::Name - String table for a TTF font
+
+=head1 DESCRIPTION
+
+Strings are held by number, platform, encoding and language. Strings are
+accessed as:
+
+ $f->{'name'}{'strings'}[$number][$platform_id][$encoding_id]{$language_id}
+
+Notice that the language is held in an associative array due to its sparse
+nature on some platforms such as Microsoft ($pid = 3). Notice also that the
+array order is different from the stored array order (platform, encoding,
+language, number) to allow for easy manipulation of strings by number (which is
+what I guess most people will want to do).
+
+By default, C<$Font::TTF::Name::utf8> is set to 1, and strings will be stored as UTF8 wherever
+possible. The method C<is_utf8> can be used to find out if a string in a particular
+platform and encoding will be returned as UTF8. Unicode strings are always
+converted if utf8 is requested. Otherwise, strings are stored according to platform:
+
+ ***WARNING NON-UTF8 is deprecated and utf8 strings has become the default***
+
+You now have to set <$Font::TTF::Name::utf8> to 0 to get the old behaviour.
+
+=over 4
+
+=item Apple Unicode (platform id = 0)
+
+Data is stored as network ordered UCS2. There is no encoding id for this platform
+but there are language ids as per Mac language ids.
+
+=item Mac (platform id = 1)
+
+Data is stored as 8-bit binary data, leaving the interpretation to the user
+according to encoding id.
+
+=item Unicode (platform id = 2)
+
+Currently stored as 16-bit network ordered UCS2. Upon release of Perl 5.005 this
+will change to utf8 assuming current UCS2 semantics for all encoding ids.
+
+=item Windows (platform id = 3)
+
+As per Unicode, the data is currently stored as 16-bit network ordered UCS2. Upon
+release of Perl 5.005 this will change to utf8 assuming current UCS2 semantics for
+all encoding ids.
+
+=back
+
+=head1 INSTANCE VARIABLES
+
+=over 4
+
+=item strings
+
+An array of arrays, etc.
+
+=back
+
+=head1 METHODS
+
+=cut
+
+use strict;
+use vars qw(@ISA $VERSION @apple_encs @apple_encodings $utf8 $cp_1252 @cp_1252);
+use Font::TTF::Table;
+use Font::TTF::Utils;
+ at ISA = qw(Font::TTF::Table);
+
+$utf8 = 1;
+
+{
+ my ($count, $i);
+ eval {require Compress::Zlib;};
+ unless ($@)
+ {
+ for ($i = 0; $i <= $#apple_encs; $i++)
+ {
+ $apple_encodings[0][$i] = [unpack("n*", Compress::Zlib::uncompress(unpack("u", $apple_encs[$i])))]
+ if (defined $apple_encs[$i]);
+ $count = 0;
+ $apple_encodings[1][$i] = {map({$_ => $count++} @{$apple_encodings[0][$i]})};
+ }
+ $cp_1252[0] = [unpack("n*", Compress::Zlib::uncompress(unpack("u", $cp_1252)))];
+ $count = 0;
+ $cp_1252[1] = {map({$_ => $count++} @{$cp_1252[0]})};
+ }
+}
+
+
+$VERSION = 1.1; # MJPH 17-JUN-2000 Add utf8 support
+# $VERSION = 1.001; # MJPH 10-AUG-1998 Put $number first in list
+
+=head2 $t->read
+
+Reads all the names into memory
+
+=cut
+
+sub read
+{
+ my ($self) = @_;
+ my ($fh) = $self->{' INFILE'};
+ my ($dat, $num, $stroff, $i, $pid, $eid, $lid, $nid, $len, $off, $here);
+
+ $self->SUPER::read or return $self;
+ $fh->read($dat, 6);
+ ($num, $stroff) = unpack("x2nn", $dat);
+ for ($i = 0; $i < $num; $i++)
+ {
+ use bytes; # hack to fix bugs in 5.8.7
+ read($fh, $dat, 12);
+ ($pid, $eid, $lid, $nid, $len, $off) = unpack("n6", $dat);
+ $here = $fh->tell();
+ $fh->seek($self->{' OFFSET'} + $stroff + $off, 0);
+ $fh->read($dat, $len);
+ if ($utf8)
+ {
+ if ($pid == 1 && defined $apple_encodings[0][$eid])
+ { $dat = TTF_word_utf8(pack("n*", map({$apple_encodings[0][$eid][$_]} unpack("C*", $dat)))); }
+ elsif ($pid == 2 && $eid == 2 && defined @cp_1252)
+ { $dat = TTF_word_utf8(pack("n*", map({$cp_1252[0][$_]} unpack("C*", $dat)))); }
+ elsif ($pid == 0 || $pid == 3 || ($pid == 2 && $eid == 1))
+ { $dat = TTF_word_utf8($dat); }
+ }
+ $self->{'strings'}[$nid][$pid][$eid]{$lid} = $dat;
+ $fh->seek($here, 0);
+ }
+ $self;
+}
+
+
+=head2 $t->out($fh)
+
+Writes out all the strings
+
+=cut
+
+sub out
+{
+ my ($self, $fh) = @_;
+ my ($pid, $eid, $lid, $nid, $todo, @todo);
+ my ($len, $offset, $loc, $stroff, $endloc, $str_trans);
+
+ return $self->SUPER::out($fh) unless $self->{' read'};
+
+ $loc = $fh->tell();
+ $fh->print(pack("n3", 0, 0, 0));
+ foreach $nid (0 .. $#{$self->{'strings'}})
+ {
+ foreach $pid (0 .. $#{$self->{'strings'}[$nid]})
+ {
+ foreach $eid (0 .. $#{$self->{'strings'}[$nid][$pid]})
+ {
+ foreach $lid (sort keys %{$self->{'strings'}[$nid][$pid][$eid]})
+ {
+ $str_trans = $self->{'strings'}[$nid][$pid][$eid]{$lid};
+ if ($utf8)
+ {
+ if ($pid == 1 && defined $apple_encodings[1][$eid])
+ { $str_trans = pack("C*",
+ map({$apple_encodings[1][$eid]{$_} || "?"} unpack("n*",
+ TTF_utf8_word($str_trans)))); }
+ elsif ($pid == 2 && $eid == 2 && defined @cp_1252)
+ { $str_trans = pack("C*",
+ map({$cp_1252[1][$eid]{$_} || "?"} unpack("n*",
+ TTF_utf8_word($str_trans)))); }
+ elsif ($pid == 2 && $eid == 0)
+ { $str_trans =~ s/[\xc0-\xff][\x80-\xbf]+/?/og; }
+ elsif ($pid == 0 || $pid == 3 || ($pid == 2 && $eid == 1))
+ { $str_trans = TTF_utf8_word($str_trans); }
+ }
+ push (@todo, [$pid, $eid, $lid, $nid, $str_trans]);
+ }
+ }
+ }
+ }
+
+ $offset = 0;
+ @todo = (sort {$a->[0] <=> $b->[0] || $a->[1] <=> $b->[1] || $a->[2] <=> $b->[2]
+ || $a->[3] <=> $b->[3]} @todo);
+ foreach $todo (@todo)
+ {
+ $len = length($todo->[4]);
+ $fh->print(pack("n6", @{$todo}[0..3], $len, $offset));
+ $offset += $len;
+ }
+
+ $stroff = $fh->tell() - $loc;
+ foreach $todo (@todo)
+ { $fh->print($todo->[4]); }
+
+ $endloc = $fh->tell();
+ $fh->seek($loc, 0);
+ $fh->print(pack("n3", 0, $#todo + 1, $stroff));
+ $fh->seek($endloc, 0);
+ $self;
+}
+
+
+=head2 $t->XML_element($context, $depth, $key, $value)
+
+Outputs the string element in nice XML (which is all the table really!)
+
+=cut
+
+sub XML_element
+{
+ my ($self) = shift;
+ my ($context, $depth, $key, $value) = @_;
+ my ($fh) = $context->{'fh'};
+ my ($nid, $pid, $eid, $lid);
+
+ return $self->SUPER::XML_element(@_) unless ($key eq 'strings');
+
+ foreach $nid (0 .. $#{$self->{'strings'}})
+ {
+ next unless ref($self->{'strings'}[$nid]);
+# $fh->print("$depth<strings id='$nid'>\n");
+ foreach $pid (0 .. $#{$self->{'strings'}[$nid]})
+ {
+ foreach $eid (0 .. $#{$self->{'strings'}[$nid][$pid]})
+ {
+ foreach $lid (sort {$a <=> $b} keys %{$self->{'strings'}[$nid][$pid][$eid]})
+ {
+ $fh->printf("%s<string id='%s' platform='%s' encoding='%s' language='%s'>\n%s%s%s\n%s</string>\n",
+ $depth, $nid, $pid, $eid, $lid, $depth,
+ $context->{'indent'}, $self->{'strings'}[$nid][$pid][$eid]{$lid}, $depth);
+ }
+ }
+ }
+# $fh->print("$depth</strings>\n");
+ }
+ $self;
+}
+
+
+=head2 $t->XML_end($context, $tag, %attrs)
+
+Store strings in the right place
+
+=cut
+
+sub XML_end
+{
+ my ($self) = shift;
+ my ($context, $tag, %attrs) = @_;
+
+ if ($tag eq 'string')
+ {
+ $self->{'strings'}[$attrs{'id'}][$attrs{'platform'}][$attrs{'encoding'}]{$attrs{'language'}}
+ = $context->{'text'};
+ return $context;
+ }
+ else
+ { return $self->SUPER::XML_end(@_); }
+}
+
+=head2 is_utf8($pid, $eid)
+
+Returns whether a string of a given platform and encoding is going to be in UTF8
+
+=cut
+
+sub is_utf8
+{
+ my ($self, $pid, $eid) = @_;
+
+ return ($utf8 && ($pid == 0 || $pid == 3 || ($pid == 2 && ($eid != 2 || defined @cp_1252))
+ || ($pid == 1 && defined $apple_encodings[$eid])));
+}
+
+
+=head2 find_name($nid)
+
+Hunts down a name in all the standard places and returns the string and for an
+array context the pid, eid & lid as well
+
+=cut
+
+sub find_name
+{
+ my ($self, $nid) = @_;
+ my ($res, $pid, $eid, $lid, $look, $k);
+
+ my (@lookup) = ([3, 1, 1033], [3, 1, -1], [3, 0, 1033], [3, 0, -1], [2, 1, -1], [2, 2, -1], [2, 0, -1],
+ [0, 0, 0], [1, 0, 0]);
+ foreach $look (@lookup)
+ {
+ ($pid, $eid, $lid) = @$look;
+ if ($lid == -1)
+ {
+ foreach $k (keys %{$self->{'strings'}[$nid][$pid][$eid]})
+ {
+ if (($res = $self->{strings}[$nid][$pid][$eid]{$k}) ne '')
+ {
+ $lid = $k;
+ last;
+ }
+ }
+ } else
+ { $res = $self->{strings}[$nid][$pid][$eid]{$lid} }
+ if ($res ne '')
+ { return wantarray ? ($res, $pid, $eid, $lid) : $res; }
+ }
+ return '';
+}
+
+
+BEGIN {
+ at apple_encs = (
+<<'EOT',
+M>)RES==NCW$`@.'G_S5Q*L(!#?+K1VO4:.W6IJA-:\^BM?>L>1&NP(A0Q$BL
+M<*!62ZV8Z1)[K]BE$MR#O,=/7OW]7T&*6"NMI4K31EOMM)>N at XXZZ2Q#IBZZ
+MZJ:['GKJ)4NVWOKHJ]\_/\!`@PR68XBAALDUW`@CC3+:&&.-,UZ>?!-,-,ED
+M4TPUS70SS#3+;`7FF&N>0D7F6V"A119;8JEEEEMAI5566V.M==;;H-A&FVRV
+MQ5;;_OTONJ3<%;?<5^NQ1YYXYJGG7GKME3?>>N^=#S[ZY(O/OOKNFU]^JO<[
+M!$?LLMO>$#OAH4-*4F+'[(L+E*F,6SH:%\9%]C@>1W&CN&%2:9QNO]-))5ZH
+M<]9.!^/DQ/8X-V[@@#,AS0ZE+KB7R$ODA\:A26@>6H2FH9D?J17^)(I#3C at 8
+MLD)V?:(^"BE.AN30,F0XK\(Y5UUVW0TW77/'W;H_;JM6HRJ1&95%M0Y'E5%5
+.5.U4]""JB<K_`B>`?E$`
+EOT
+
+undef,
+undef,
+undef,
+<<'EOT',
+M>)RES[=/%```1O$WO8G_@$'J';W70Z2WHS>5WJN%8D6%D;BZ,3*P,;#C2D(8
+M,9&)08V)+4*(1((X2'(#[.:;7[[\*./_%D,L<<230"(!@B213`JII)%.!IED
+MD4T.N>213P&%%%%,B!)N4LJMR[Z<"BJIHIH::JFCG@;"--)$,RVTTD8['732
+M13>WN<-=>NBECWX&&&2(848898QQ)IADBFEFF.4>]WG`0^:89X%%'O&8)SSE
+M&<]9X at 4O><4R*Y?_.ZRSRQ[[''#(1S[PB<]NL\D7OO&5[_S at 9TR`(XXYX1=O
+M.>4W9_SAG`O^7OF=O>XW*N)WV!%''7/<"2>=<MH90D9'_-X(AHTUSG at 33#1@
+MT"2333'5--/-,-,LL\TQUSSS+;#0(HL-7?DMM\)*JZRVQEKKK+?!L(TVV6R+
+9K;;9;H<K+KGJ>S?<\K5O(G[7?/</+>Y>'```
+EOT
+
+<<'EOT',
+M>)RED$LSEW$`A9_-^00L,H-^(=>4Y%^2J'1Q*Y+[I2(BHA`B?!%J6EM1*28S
+M;9II[/PI*7*_%TUN\_*VZ%W:FN9LSYEGGD,\_Q?#$?SP)X"C!!)$,"&$$L8Q
+MPCG."2(X222GB,+%:<X0S5EB.$<LYXES]A>XR"42N,P5KG*-1))()H54KG.#
+M--*Y20:WR"2+;'+()8]\"BBDB-O<X2[%E'"/4LJX3SD5/*"2*AY230V/>$PM
+M==3SA`8::>(IS;3PC%;::'?X'^W#?&(0-Z-,,,,TL\PSQP)+K+#,*C]9XQ?K
+M_.8/FVRPQ0[;[+&+S=_]_J;KX/Y6I?&U.JQ.Z[GU0 at -VBNTR@;Q4G]ZI5V_U
+MQG at 83^-M?,PAXV6'VF'ZH&Z]4H_>J]]IO=:0W!K6B#[KBT;U56/ZIN\:UX1^
+?:%)3FM:,9C6G>2UH44M:UHI6'?<BYX,"6O\!%-%\5```
+EOT
+
+<<'EOT',
+M>)RES5=OSG$`0.$CYR.(A(3DUS]J4WOO59O6;&F+UMY[7R&(V'N^4ETZ=*"J
+M:M:H=>E*0D1B)7HC1KC0[R#G^LEA,/]7((Z(EK2B-?&TH2WM:$\'.M*)SG0A
+M@:YTHSL]Z$DO>M.'OO2C/P,8R*`&/X2A#&,X(QC)*$:3R!C&,H[Q3&`BDYC,
+M%))(9BK3F,X,9C*+%%*9S1S22">#N<QC/IEDL8"%+&(Q2UC*,I:S at I6L8C5K
+M6,LZUK.!C6QB,UO8RC:VLZ/A7TL5Y=11P6O>N(MWO.>#.\GG(Y_YQ!>^DAT7
+M\8WZ$%$3$OC.#W(IYC=_^!N"1SWF*<]ZP1AO*:'`;*^0%V502J6'*8LRHRQR
+M/.)Q3WC2TY[QG+D6FF^!19ZGR(M>BA*]3"'5(9Z8.>:YVSV-DD/CT"0T#RU"
+MT]",G^YUG_L]8+$E7O6%!WUIF>4^]9K7?6R%E59YQUM6>]L:[WK/5][WH;7>
+4M,X'/O&1-WSF<P]9^BOV#YW%>_\`
+EOT
+
+<<'EOT',
+M>)RERT=.%5``0-&+7K'&!B(@X/L/^/3>ZZ?SZ=*K@`KVWOL:U!68.#!&8G2@
+M$Q?F5/=@SOB0XO\$$D2**:&4)&644T$E55130RUUU--`(TTTTT(K;;3302==
+M=--#[[_?1S\###+$,".,DF:,<2:89(II9KC`+'/,L\`B2RRSPBIKK+/!13;9
+M8IM+7.8*.^QRE6M<YP8WN<5M[G"7>]SG`0]YQ&.>\)1G/.<%+WG%:][PEI0G
+M/>5IL\SVC#F>-=<\\SUG at 846>=Y at PFBQ)9::M,QR*ZRTRFIKK+4N!+[[CD]\
+M#I%?9O*-+XGH/N?BMON=CT7\B#MQUR5^^MY#ZH('7?:PJQYQS14/L!?S,S[$
+M=,SD*[]#DH\>==UC;K at 8LD)V*`B%(3?D\2<4>=Q-3[B5R#'#66>LM\%&FVRV
+GQ5;;;+?#3KOLML=>4_;9[X"##CGLB*.F'7/<"2>=<CKL_06V`DD#
+EOT
+
+undef,
+<<'EOT',
+M>)RED-DVUG$`1;=:U*Y%0C)5O^^/SSS/F>>9#"$JE7D>"D6\3S=>Q^MPU^JF
+M&^M<G[7//G1ROP1B1.130"%QBBBFA%+***>"2JJHIH9:ZJBG at 4:::*:%M[32
+M1CL==_TNNNFAES[Z&6"0(889890QQIE at DG=,,<T,L[QGCGD6^,`B2WSD$Y]9
+MY at M?^<8*JZRQS@:;;+'-#KOLL<\!AQQQS'=^<,(I9_SD%^=<\)M+KN[X-U%:
+M2`\9(2MDAWB(^,-U+/KKYYJ'_W_`!!_XT$23?.1C]8E/3?&9J2:;9KH9/O>%
+MF;XTRVQSS#7/5[[VC<&8D?D66&C<(HLML=0RRZVPTBJ7K;;&6NNLM\%&FVRV
+L):388:===MMCKP,..F2_(XXZYK#CMKGZS[YU-]QTRVUWW'7/?0]N`4(?0WT`
+EOT
+
+<<'EOT',
+M>)RED,5.0U$415=(D.X!$"ANMX^VN+M#D>+N[H4"Q5W^APF_PZ\PY.9-"`-&
+MY.3LG>-"#_\3 at P^'8OP$"%)"*6644T$E55130RUUU--`(TTTTT(K;;3302==
+M=-OZ7OH(T<\`@PP19I at 11AECG`DFF6*:&6:98YX%%EEBF15666.=#3;98IL=
+M=MECGP,.B7#$,5%...6,&.=<<,D5U]QPRQWW//#($\^\\,J;G?_II)ETXS79
+M)L<$C<,['S[GYSY=?FWK6E>Z^?L'BK,:KP0E*DD>R?6E*-7E='DM9BA36<I6
+MCG*5IWP5J%!%,O+)4;'\"BBH$I7:S')5J%)5JE:-M6JMUKM]FM1LL55M)EG=
+GZE&O^A1R(V$-NSRF<8L3ZO3L_]KN4!$=Z5A1G>A49XKI_!M<9D8J
+EOT
+
+<<'EOT',
+M>)RED,E3SW$8QU_77@<''+A]^Y5(2-F7+"%92\B^ES5ES]H,)L(8&21E*UNH
+M&"8T8ZS3I(FS_T"$_`L^-^/D8)YY/^]Y/\L\"Y/Y/XN()T8"B0P at B8$,(IG!
+MI#"$H0PCE>&DD<X(1C**T8QA+.,8SP0FDL&DT#^%J60RC>G,((N99#.+V<QA
+M+O.83PZY+""/A2QB,?DL82G+6,X*5K**U:QA+>M8SP8**&0CF]C,%K:RC2*V
+M4TP).]C)+G:SA[WLHY3]'.`@ASC,$<K"_,^QWE&?J&_4+^H?)44Q[M,<'_MS
+M7USAOS[@48]YW')/>-(*3WG:,R%ZSDK/!K[@1<][R2HO6^T5:ZSUJM>\[@UO
+M6F>]M[SM'>]ZSX90_\"'-MIDLX^">ASPQ*?!M_C,Y[ZP->KE*U_[QK>^\WW(
+CM/O!ML"=?K3#3[Z,*_AKOR]V^=5O=OO='_ZTQU^_`2-%:*``
+EOT
+
+undef,
+undef,
+undef,
+undef,
+undef,
+undef,
+undef,
+undef,
+undef,
+<<'EOT',
+M>)REC]=.E&$`1(\%&W at 4004%_7:!I?>.Z-+[TJL*=K"`BH`*J,_"+2'A!7PW
+MX;\2[LG<3#*9G!F2G$V!&'$***2(!,644$H9Y5102175U%!+'?4TT$@3S;30
+M2AN/:.<Q3Z)^!YUTT4T/O?31SP"###',""E&&6.<"2:98IH99IECG at 6>\HSG
+M+++$"U[RBM>\X2WO6&:%]WS@(Y]898W/?.$KZWQC at TVV^,X/?K+-#KO\XC=_
+M(OX!?T/"`0<=<MB1$Q?R0KXIDB%NK?TVV&B3S:?RG)`;]?<\YWDO>-$T+WG9
+M*U[UFNEF>%V]X4TSO666V=[VCG?-,==[WC?/?!_XT&#,N`466F3"8DLLM<QR
+M*ZRTRFIK(GJ=]?_Y+;;:]N\HI(>LD&W2#COMLML>>^V+=IX\2<7BCCGNA)-.
+0.>V,L\XY[P*'[!\#D^='L@``
+EOT
+
+undef,
+undef,
+undef,
+undef,
+undef,
+undef,
+undef,
+undef,
+undef,
+);
+
+$cp_1252 = (
+<<'EOT',
+M>)P-SD-B'5```,#YJ6VE>DEM&[\VD]JVF?H./4'-U+93V[9M:SV;$141(Y74
+MTD at KG?0RR"B3S++(*IOL<L at IE]SRR"N?_`J(55`AA1515!`G7C'%E5!2*:65
+M458YY550426555%5-=754%,MM=515SWU-=!05".--=%4,\VUT%(KK;715COM
+M==!1)YTE2-1%5]UTUT-/O?361U_]]#?`0(,,-L10PPPWPDBCC#;&6..,-\%$
+MDTPVQ5333)=DAIEFF6V.N>:%9-$0&YD?BH22(82XF)10.3(@U(DDB$;F_/]%
+M0_Y0(!0*A4-\R!5RQ]R*BX\,#'4CB?]];B3)`@LMLM at 22RVSW`HKK;):LC76
+M6F>]#3;:9+,MMMIFNQUVVF6W/?;:9[\##CKDL"-2''7,<2><=,II9YQUSGD7
+M7'3)95=<=<UU-]QTRVUWW'7/?0\\],AC3SSUS',OO/3*:V^\]<Y['WSTR6=?
+1?/7-=S_\],MO?_S]!Y==>0@`
+EOT
+);
+}
+
+1;
+
+=head1 BUGS
+
+=over 4
+
+=item *
+
+Unicode type strings will be stored in utf8 for all known platforms,
+once Perl 5.6 has been released and I can find all the mapping tables, etc.
+
+=back
+
+=head1 AUTHOR
+
+Martin Hosken Martin_Hosken at sil.org. See L<Font::TTF::Font> for copyright and
+licensing.
+
+=cut
+
Modified: packages/libfont-ttf-perl/trunk/lib/Font/TTF/OS_2.pm
===================================================================
--- packages/libfont-ttf-perl/trunk/lib/Font/TTF/OS_2.pm 2006-01-17 02:56:43 UTC (rev 1966)
+++ packages/libfont-ttf-perl/trunk/lib/Font/TTF/OS_2.pm 2006-01-17 03:07:20 UTC (rev 1967)
@@ -1,306 +1,323 @@
-package Font::TTF::OS_2;
-
-=head1 NAME
-
-Font::TTF::OS_2 - the OS/2 table in a TTF font
-
-=head1 DESCRIPTION
-
-The OS/2 table has two versions and forms, one an extension of the other. This
-module supports both forms and the switching between them.
-
-=head1 INSTANCE VARIABLES
-
-No other variables than those in table and those in the standard:
-
- Version
- xAvgCharWidth
- usWeightClass
- usWidthClass
- fsType
- ySubscriptXSize
- ySubScriptYSize
- ySubscriptXOffset
- ySubscriptYOffset
- ySuperscriptXSize
- ySuperscriptYSize
- ySuperscriptXOffset
- ySuperscriptYOffset
- yStrikeoutSize
- yStrikeoutPosition
- sFamilyClass
- bFamilyType
- bSerifStyle
- bWeight
- bProportion
- bContrast
- bStrokeVariation
- bArmStyle
- bLetterform
- bMidline
- bXheight
- ulUnicodeRange1
- ulUnicodeRange2
- ulUnicodeRange3
- ulUnicodeRange4
- achVendID
- fsSelection
- usFirstCharIndex
- usLastCharIndex
- sTypoAscender
- sTypoDescender
- sTypoLineGap
- usWinAscent
- usWinDescent
- ulCodePageRange1
- ulCodePageRange2
- xHeight
- CapHeight
- defaultChar
- breakChar
- maxLookups
-
-Notice that versions 0, 1 & 2 of the table are supported. Notice also that the
-Panose variable has been broken down into its elements.
-
-=head1 METHODS
-
-=cut
-
-use strict;
-use vars qw(@ISA @fields @lens @field_info);
-use Font::TTF::Table;
-
- at ISA = qw(Font::TTF::Table);
- at field_info = (
- 'xAvgCharWidth' => 's',
- 'usWeightClass' => 'S',
- 'usWidthClass' => 'S',
- 'fsType' => 's',
- 'ySubscriptXSize' => 's',
- 'ySubScriptYSize' => 's',
- 'ySubscriptXOffset' => 's',
- 'ySubscriptYOffset' => 's',
- 'ySuperscriptXSize' => 's',
- 'ySuperscriptYSize' => 's',
- 'ySuperscriptXOffset' => 's',
- 'ySuperscriptYOffset' => 's',
- 'yStrikeoutSize' => 's',
- 'yStrikeoutPosition' => 's',
- 'sFamilyClass' => 's',
- 'bFamilyType' => 'C',
- 'bSerifStyle' => 'C',
- 'bWeight' => 'C',
- 'bProportion' => 'C',
- 'bContrast' => 'C',
- 'bStrokeVariation' => 'C',
- 'bArmStyle' => 'C',
- 'bLetterform' => 'C',
- 'bMidline' => 'C',
- 'bXheight' => 'C',
- 'ulUnicodeRange1' => 'L',
- 'ulUnicodeRange2' => 'L',
- 'ulUnicodeRange3' => 'L',
- 'ulUnicodeRange4' => 'L',
- 'achVendID' => 'L',
- 'fsSelection' => 'S',
- 'usFirstCharIndex' => 'S',
- 'usLastCharIndex' => 'S',
- 'sTypoAscender' => 'S',
- 'sTypoDescender' => 's',
- 'sTypoLineGap' => 'S',
- 'usWinAscent' => 'S',
- 'usWinDescent' => 'S',
- '' => '',
- 'ulCodePageRange1' => 'L',
- 'ulCodePageRange2' => 'L',
- '' => '',
- 'xHeight' => 's',
- 'CapHeight' => 's',
- 'defaultChar' => 'S',
- 'breakChar' => 'S',
- 'maxLookups' => 's');
-
-use Font::TTF::Utils;
-
-sub init
-{
- my ($k, $v, $c, $n, $i, $t, $j);
-
- $n = 0;
- @lens = (76, 84, 94);
- for ($j = 0; $j < $#field_info; $j += 2)
- {
- if ($field_info[$j] eq '')
- {
- $n++;
- next;
- }
- ($k, $v, $c) = TTF_Init_Fields($field_info[$j], $c, $field_info[$j+1]);
- next unless defined $k && $k ne "";
- for ($i = $n; $i < 3; $i++)
- { $fields[$i]{$k} = $v; }
- }
-}
-
-
-=head2 $t->read
-
-Reads in the various values from disk (see details of OS/2 table)
-
-=cut
-
-sub read
-{
- my ($self) = @_;
- my ($dat, $ver);
-
- $self->SUPER::read or return $self;
-
- init unless defined $fields[2]{'xAvgCharWidth'};
- $self->{' INFILE'}->read($dat, 2);
- $ver = unpack("n", $dat);
- $self->{'Version'} = $ver;
- if ($ver < 3)
- {
- $self->{' INFILE'}->read($dat, $lens[$ver]);
- TTF_Read_Fields($self, $dat, $fields[$ver]);
- }
- $self;
-}
-
-
-=head2 $t->out($fh)
-
-Writes the table to a file either from memory or by copying.
-
-=cut
-
-sub out
-{
- my ($self, $fh) = @_;
- my ($ver);
-
- return $self->SUPER::out($fh) unless $self->{' read'};
-
- $ver = $self->{'Version'};
- $fh->print(pack("n", $ver));
- $fh->print(TTF_Out_Fields($self, $fields[$ver], $lens[$ver]));
- $self;
-}
-
-
-=head2 $t->XML_element($context, $depth, $key, $value)
-
-Tidies up the hex values to output them in hex
-
-=cut
-
-sub XML_element
-{
- my ($self) = shift;
- my ($context, $depth, $key, $value) = @_;
- my ($fh) = $context->{'fh'};
-
- if ($key =~ m/^ul(?:Unicode|CodePage)Range\d$/o)
- { $fh->printf("%s<%s>%08X</%s>\n", $depth, $key, $value, $key); }
- elsif ($key eq 'achVendID')
- { $fh->printf("%s<%s name='%s'/>\n", $depth, $key, pack('N', $value)); }
- else
- { return $self->SUPER::XML_element(@_); }
- $self;
-}
-
-
-=head2 $t->XML_end($context, $tag, %attrs)
-
-Now handle them on the way back in
-
-=cut
-
-sub XML_end
-{
- my ($self) = shift;
- my ($context, $tag, %attrs) = @_;
-
- if ($tag =~ m/^ul(?:Unicode|CodePage)Range\d$/o)
- { return hex($context->{'text'}); }
- elsif ($tag eq 'achVendID')
- { return unpack('N', $attrs{'name'}); }
- else
- { return $self->SUPER::XML_end(@_); }
-}
-
-=head2 $t->update
-
-Updates the OS/2 table by getting information from other sources:
-
-Updates the C<firstChar> and C<lastChar> values based on the MS table in the
-cmap.
-
-Updates the sTypoAscender, sTypoDescender & sTypoLineGap to be the same values
-as Ascender, Descender and Linegap from the hhea table (assuming it is dirty)
-and also sets usWinAscent to be the sum of Ascender+Linegap and usWinDescent to
-be the negative of Descender.
-
-=cut
-
-sub update
-{
- my ($self) = @_;
- my ($map, @keys, $table);
-
- return undef unless ($self->SUPER::update);
-
- $self->{' PARENT'}{'cmap'}->update;
- $map = $self->{' PARENT'}{'cmap'}->find_ms || return undef;
-
- @keys = sort {$a <=> $b} keys %{$map->{'val'}};
-
- $self->{'usFirstCharIndex'} = $keys[0];
- $self->{'usLastCharIndex'} = $keys[-1];
-
- $table = $self->{' PARENT'}{'hhea'}->read;
-
- # try any way we can to get some real numbers passed around!
- if ($table->{'Ascender'} != 0 || $table->{'Descender'} != 0)
- {
- $self->{'sTypoAscender'} = $table->{'Ascender'};
- $self->{'sTypoDescender'} = $table->{'Descender'};
- $self->{'sTypoLineGap'} = $table->{'Linegap'};
- $self->{'usWinAscent'} = $self->{'sTypoAscender'} + $self->{'sTypoLineGap'};
- $self->{'usWinDescent'} = -$self->{'sTypoDescender'};
- }
- elsif ($self->{'sTypoAscender'} != 0 || $self->{'sTypoDescender'} != 0)
- {
- $table->{'Ascender'} = $self->{'sTypoAscender'};
- $table->{'Descender'} = $self->{'sTypoDescender'};
- $table->{'Linegap'} = $self->{'sTypoLineGap'};
- $self->{'usWinAscent'} = $self->{'sTypoAscender'} + $self->{'sTypoLineGap'};
- $self->{'usWinDescent'} = -$self->{'sTypoDescender'};
- }
- elsif ($self->{'usWinAscent'} != 0 || $self->{'usWinDescent'} != 0)
- {
- $self->{'sTypoAscender'} = $table->{'Ascender'} = $self->{'usWinAscent'};
- $self->{'sTypoDescender'} = $table->{'Descender'} = -$self->{'usWinDescent'};
- $self->{'sTypoLineGap'} = $table->{'Linegap'} = 0;
- }
-
- $self->{'Version'} = 1 if (defined $self->{'ulCodePageRange1'} && $self->{'Version'} < 1);
- $self->{'Version'} = 2 if (defined $self->{'maxLookups'} && $self->{'Version'} < 2);
-
- $self;
-}
-
-1;
-
-=head1 BUGS
-
-None known
-
-=head1 AUTHOR
-
-Martin Hosken Martin_Hosken at sil.org. See L<Font::TTF::Font> for copyright and
-licensing.
-
-=cut
+package Font::TTF::OS_2;
+
+=head1 NAME
+
+Font::TTF::OS_2 - the OS/2 table in a TTF font
+
+=head1 DESCRIPTION
+
+The OS/2 table has two versions and forms, one an extension of the other. This
+module supports both forms and the switching between them.
+
+=head1 INSTANCE VARIABLES
+
+No other variables than those in table and those in the standard:
+
+ Version
+ xAvgCharWidth
+ usWeightClass
+ usWidthClass
+ fsType
+ ySubscriptXSize
+ ySubScriptYSize
+ ySubscriptXOffset
+ ySubscriptYOffset
+ ySuperscriptXSize
+ ySuperscriptYSize
+ ySuperscriptXOffset
+ ySuperscriptYOffset
+ yStrikeoutSize
+ yStrikeoutPosition
+ sFamilyClass
+ bFamilyType
+ bSerifStyle
+ bWeight
+ bProportion
+ bContrast
+ bStrokeVariation
+ bArmStyle
+ bLetterform
+ bMidline
+ bXheight
+ ulUnicodeRange1
+ ulUnicodeRange2
+ ulUnicodeRange3
+ ulUnicodeRange4
+ achVendID
+ fsSelection
+ usFirstCharIndex
+ usLastCharIndex
+ sTypoAscender
+ sTypoDescender
+ sTypoLineGap
+ usWinAscent
+ usWinDescent
+ ulCodePageRange1
+ ulCodePageRange2
+ xHeight
+ CapHeight
+ defaultChar
+ breakChar
+ maxLookups
+
+Notice that versions 0, 1 & 2 of the table are supported. Notice also that the
+Panose variable has been broken down into its elements.
+
+=head1 METHODS
+
+=cut
+
+use strict;
+use vars qw(@ISA @fields @lens @field_info @weights);
+use Font::TTF::Table;
+
+ at ISA = qw(Font::TTF::Table);
+ at field_info = (
+ 'xAvgCharWidth' => 's',
+ 'usWeightClass' => 'S',
+ 'usWidthClass' => 'S',
+ 'fsType' => 's',
+ 'ySubscriptXSize' => 's',
+ 'ySubScriptYSize' => 's',
+ 'ySubscriptXOffset' => 's',
+ 'ySubscriptYOffset' => 's',
+ 'ySuperscriptXSize' => 's',
+ 'ySuperscriptYSize' => 's',
+ 'ySuperscriptXOffset' => 's',
+ 'ySuperscriptYOffset' => 's',
+ 'yStrikeoutSize' => 's',
+ 'yStrikeoutPosition' => 's',
+ 'sFamilyClass' => 's',
+ 'bFamilyType' => 'C',
+ 'bSerifStyle' => 'C',
+ 'bWeight' => 'C',
+ 'bProportion' => 'C',
+ 'bContrast' => 'C',
+ 'bStrokeVariation' => 'C',
+ 'bArmStyle' => 'C',
+ 'bLetterform' => 'C',
+ 'bMidline' => 'C',
+ 'bXheight' => 'C',
+ 'ulUnicodeRange1' => 'L',
+ 'ulUnicodeRange2' => 'L',
+ 'ulUnicodeRange3' => 'L',
+ 'ulUnicodeRange4' => 'L',
+ 'achVendID' => 'L',
+ 'fsSelection' => 'S',
+ 'usFirstCharIndex' => 'S',
+ 'usLastCharIndex' => 'S',
+ 'sTypoAscender' => 'S',
+ 'sTypoDescender' => 's',
+ 'sTypoLineGap' => 'S',
+ 'usWinAscent' => 'S',
+ 'usWinDescent' => 'S',
+ '' => '',
+ 'ulCodePageRange1' => 'L',
+ 'ulCodePageRange2' => 'L',
+ '' => '',
+ 'xHeight' => 's',
+ 'CapHeight' => 's',
+ 'defaultChar' => 'S',
+ 'breakChar' => 'S',
+ 'maxLookups' => 's');
+
+ at weights = qw(64 14 27 35 100 20 14 42 63 3 6 35 20 56 56 17 4 49 56 71 31 10 18 3 18 2 166);
+
+use Font::TTF::Utils;
+
+sub init
+{
+ my ($k, $v, $c, $n, $i, $t, $j);
+
+ $n = 0;
+ @lens = (76, 84, 94);
+ for ($j = 0; $j < $#field_info; $j += 2)
+ {
+ if ($field_info[$j] eq '')
+ {
+ $n++;
+ next;
+ }
+ ($k, $v, $c) = TTF_Init_Fields($field_info[$j], $c, $field_info[$j+1]);
+ next unless defined $k && $k ne "";
+ for ($i = $n; $i < 3; $i++)
+ { $fields[$i]{$k} = $v; }
+ }
+}
+
+
+=head2 $t->read
+
+Reads in the various values from disk (see details of OS/2 table)
+
+=cut
+
+sub read
+{
+ my ($self) = @_;
+ my ($dat, $ver);
+
+ $self->SUPER::read or return $self;
+
+ init unless defined $fields[2]{'xAvgCharWidth'};
+ $self->{' INFILE'}->read($dat, 2);
+ $ver = unpack("n", $dat);
+ $self->{'Version'} = $ver;
+ if ($ver < 3)
+ {
+ $self->{' INFILE'}->read($dat, $lens[$ver]);
+ TTF_Read_Fields($self, $dat, $fields[$ver]);
+ }
+ $self;
+}
+
+
+=head2 $t->out($fh)
+
+Writes the table to a file either from memory or by copying.
+
+=cut
+
+sub out
+{
+ my ($self, $fh) = @_;
+ my ($ver);
+
+ return $self->SUPER::out($fh) unless $self->{' read'};
+
+ $ver = $self->{'Version'};
+ $fh->print(pack("n", $ver));
+ $fh->print(TTF_Out_Fields($self, $fields[$ver], $lens[$ver]));
+ $self;
+}
+
+
+=head2 $t->XML_element($context, $depth, $key, $value)
+
+Tidies up the hex values to output them in hex
+
+=cut
+
+sub XML_element
+{
+ my ($self) = shift;
+ my ($context, $depth, $key, $value) = @_;
+ my ($fh) = $context->{'fh'};
+
+ if ($key =~ m/^ul(?:Unicode|CodePage)Range\d$/o)
+ { $fh->printf("%s<%s>%08X</%s>\n", $depth, $key, $value, $key); }
+ elsif ($key eq 'achVendID')
+ { $fh->printf("%s<%s name='%s'/>\n", $depth, $key, pack('N', $value)); }
+ else
+ { return $self->SUPER::XML_element(@_); }
+ $self;
+}
+
+
+=head2 $t->XML_end($context, $tag, %attrs)
+
+Now handle them on the way back in
+
+=cut
+
+sub XML_end
+{
+ my ($self) = shift;
+ my ($context, $tag, %attrs) = @_;
+
+ if ($tag =~ m/^ul(?:Unicode|CodePage)Range\d$/o)
+ { return hex($context->{'text'}); }
+ elsif ($tag eq 'achVendID')
+ { return unpack('N', $attrs{'name'}); }
+ else
+ { return $self->SUPER::XML_end(@_); }
+}
+
+=head2 $t->update
+
+Updates the OS/2 table by getting information from other sources:
+
+Updates the C<firstChar> and C<lastChar> values based on the MS table in the
+cmap.
+
+Updates the sTypoAscender, sTypoDescender & sTypoLineGap to be the same values
+as Ascender, Descender and Linegap from the hhea table (assuming it is dirty)
+and also sets usWinAscent to be the sum of Ascender+Linegap and usWinDescent to
+be the negative of Descender.
+
+=cut
+
+sub update
+{
+ my ($self) = @_;
+ my ($map, @keys, $table, $i, $avg, $hmtx);
+
+ return undef unless ($self->SUPER::update);
+
+ $self->{' PARENT'}{'cmap'}->update;
+ $map = $self->{' PARENT'}{'cmap'}->find_ms || return undef;
+ $hmtx = $self->{' PARENT'}{'hmtx'}->read;
+
+ @keys = sort {$a <=> $b} grep {$_ < 0x10000} keys %{$map->{'val'}};
+
+ $self->{'usFirstCharIndex'} = $keys[0];
+ $self->{'usLastCharIndex'} = $keys[-1];
+
+ $table = $self->{' PARENT'}{'hhea'}->read;
+
+ # try any way we can to get some real numbers passed around!
+ if ($table->{'Ascender'} != 0 || $table->{'Descender'} != 0)
+ {
+ $self->{'sTypoAscender'} = $table->{'Ascender'};
+ $self->{'sTypoDescender'} = $table->{'Descender'};
+ $self->{'sTypoLineGap'} = $table->{'LineGap'};
+ $self->{'usWinAscent'} = $self->{'sTypoAscender'} + $self->{'sTypoLineGap'};
+ $self->{'usWinDescent'} = -$self->{'sTypoDescender'};
+ }
+ elsif ($self->{'sTypoAscender'} != 0 || $self->{'sTypoDescender'} != 0)
+ {
+ $table->{'Ascender'} = $self->{'sTypoAscender'};
+ $table->{'Descender'} = $self->{'sTypoDescender'};
+ $table->{'LineGap'} = $self->{'sTypoLineGap'};
+ $self->{'usWinAscent'} = $self->{'sTypoAscender'} + $self->{'sTypoLineGap'};
+ $self->{'usWinDescent'} = -$self->{'sTypoDescender'};
+ }
+ elsif ($self->{'usWinAscent'} != 0 || $self->{'usWinDescent'} != 0)
+ {
+ $self->{'sTypoAscender'} = $table->{'Ascender'} = $self->{'usWinAscent'};
+ $self->{'sTypoDescender'} = $table->{'Descender'} = -$self->{'usWinDescent'};
+ $self->{'sTypoLineGap'} = $table->{'LineGap'} = 0;
+ }
+
+ for ($i = 0; $i < 26; $i++)
+ { $avg += $hmtx->{'advance'}[$map->{'val'}{$i + 0x0061}] * $weights[$i]; }
+ $avg += $hmtx->{'advance'}[$map->{'val'}{0x0020}] * $weights[-1];
+ $self->{'xAvgCharWidth'} = $avg / 1000;
+
+ foreach $i (keys %{$map->{'val'}})
+ {
+ if ($i >= 0x10000)
+ {
+ $self->{'ulUnicodeRange2'} |= 0x2000000;
+ last;
+ }
+ }
+
+ $self->{'Version'} = 1 if (defined $self->{'ulCodePageRange1'} && $self->{'Version'} < 1);
+ $self->{'Version'} = 2 if (defined $self->{'maxLookups'} && $self->{'Version'} < 2);
+
+ $self;
+}
+
+1;
+
+=head1 BUGS
+
+None known
+
+=head1 AUTHOR
+
+Martin Hosken Martin_Hosken at sil.org. See L<Font::TTF::Font> for copyright and
+licensing.
+
+=cut
Modified: packages/libfont-ttf-perl/trunk/lib/Font/TTF/OldCmap.pm
===================================================================
--- packages/libfont-ttf-perl/trunk/lib/Font/TTF/OldCmap.pm 2006-01-17 02:56:43 UTC (rev 1966)
+++ packages/libfont-ttf-perl/trunk/lib/Font/TTF/OldCmap.pm 2006-01-17 03:07:20 UTC (rev 1967)
@@ -1,358 +1,358 @@
-package Font::TTF::OldCmap;
-
-=head1 NAME
-
-Font::TTF::OldCmap - Character map table
-
-This module is deprecated
-
-=head1 DESCRIPTION
-
-Looks after the character map. The primary structure used for handling a cmap
-is the L<Font::TTF::Segarr> which handles the segmented arrays of format 4 tables,
-and in a simpler form for format 0 tables.
-
-Due to the complexity of working with segmented arrays, most of the handling of
-such arrays is via methods rather than via instance variables.
-
-One important feature of a format 4 table is that it always contains a segment
-with a final address of 0xFFFF. If you are creating a table from scratch this is
-important (although L<Font::TTF::Segarr> can work quite happily without it).
-
-
-=head1 INSTANCE VARIABLES
-
-The instance variables listed here are not preceeded by a space due to their
-emulating structural information in the font.
-
-=over 4
-
-=item Num
-
-Number of subtables in this table
-
-=item Tables
-
-An array of subtables ([0..Num-1])
-
-=back
-
-Each subtables also has its own instance variables which are, again, not
-preceeded by a space.
-
-=over 4
-
-=item Platform
-
-The platform number for this subtable
-
-=item Encoding
-
-The encoding number for this subtable
-
-=item Format
-
-Gives the stored format of this subtable
-
-=item Ver
-
-Gives the version (or language) information for this subtable
-
-=item val
-
-This points to a L<Font::TTF::Segarr> which contains the content of the particular
-subtable.
-
-=back
-
-=head1 METHODS
-
-=cut
-
-use strict;
-use vars qw(@ISA);
-require Font::TTF::Table;
-require Font::TTF::Segarr;
-
- at ISA = qw(Font::TTF::Table);
-
-
-=head2 $t->read
-
-Reads the cmap into memory. Format 4 subtables read the whole subtable and
-fill in the segmented array accordingly.
-
-Format 2 subtables are not read at all.
-
-=cut
-
-sub read
-{
- my ($self) = @_;
- my ($dat, $i, $j, $k, $id, @ids, $s);
- my ($start, $end, $range, $delta, $form, $len, $num, $ver);
- my ($fh) = $self->{' INFILE'};
-
- $self->SUPER::read or return $self;
- $fh->read($dat, 4);
- $self->{'Num'} = unpack("x2n", $dat);
- $self->{'Tables'} = [];
- for ($i = 0; $i < $self->{'Num'}; $i++)
- {
- $s = {};
- $fh->read($dat, 8);
- ($s->{'Platform'}, $s->{'Encoding'}, $s->{'LOC'}) = (unpack("nnN", $dat));
- $s->{'LOC'} += $self->{' OFFSET'};
- push(@{$self->{'Tables'}}, $s);
- }
- for ($i = 0; $i < $self->{'Num'}; $i++)
- {
- $s = $self->{'Tables'}[$i];
- $fh->seek($s->{'LOC'}, 0);
- $fh->read($dat, 6);
- ($form, $len, $ver) = (unpack("n3", $dat));
-
- $s->{'Format'} = $form;
- $s->{'Ver'} = $ver;
- if ($form == 0)
- {
- $s->{'val'} = Font::TTF::Segarr->new;
- $fh->read($dat, 256);
- $s->{'val'}->fastadd_segment(0, 2, unpack("C*", $dat));
- $s->{'Start'} = 0;
- $s->{'Num'} = 256;
- } elsif ($form == 6)
- {
- my ($start, $ecount);
-
- $fh->read($dat, 4);
- ($start, $ecount) = unpack("n2", $dat);
- $fh->read($dat, $ecount << 1);
- $s->{'val'} = Font::TTF::Segarr->new;
- $s->{'val'}->fastadd_segment($start, 2, unpack("n*", $dat));
- $s->{'Start'} = $start;
- $s->{'Num'} = $ecount;
- } elsif ($form == 2)
- {
-# no idea what to do here yet
- } elsif ($form == 4)
- {
- $fh->read($dat, 8);
- $num = unpack("n", $dat);
- $num >>= 1;
- $fh->read($dat, $len - 14);
- $s->{'val'} = Font::TTF::Segarr->new;
- for ($j = 0; $j < $num; $j++)
- {
- $end = unpack("n", substr($dat, $j << 1, 2));
- $start = unpack("n", substr($dat, ($j << 1) + ($num << 1) + 2, 2));
- $delta = unpack("n", substr($dat, ($j << 1) + ($num << 2) + 2, 2));
- $delta -= 65536 if $delta > 32767;
- $range = unpack("n", substr($dat, ($j << 1) + $num * 6 + 2, 2));
- @ids = ();
- for ($k = $start; $k <= $end; $k++)
- {
- if ($range == 0)
- { $id = $k + $delta; }
- else
- { $id = unpack("n", substr($dat, ($j << 1) + $num * 6 +
- 2 + ($k - $start) * 2 + $range, 2)) + $delta; }
- $id -= 65536 if $id > 65536;
- push (@ids, $id);
- }
- $s->{'val'}->fastadd_segment($start, 0, @ids);
- }
- $s->{'val'}->tidy;
- $s->{'Num'} = 0x10000; # always ends here
- $s->{'Start'} = $s->{'val'}[0]{'START'};
- }
- }
- $self;
-}
-
-
-=head2 $t->ms_lookup($uni)
-
-Given a Unicode value in the MS table (Platform 3, Encoding 1) locates that
-table and looks up the appropriate glyph number from it.
-
-=cut
-
-sub ms_lookup
-{
- my ($self, $uni) = @_;
-
- $self->find_ms || return undef unless (defined $self->{' mstable'});
- return $self->{' mstable'}{'val'}->at($uni);
-}
-
-
-=head2 $t->find_ms
-
-Finds the Microsoft Unicode table and sets the C<mstable> instance variable
-to it if found. Returns the table it finds.
-
-=cut
-sub find_ms
-{
- my ($self) = @_;
- my ($i, $s, $alt);
-
- return $self->{' mstable'} if defined $self->{' mstable'};
- $self->read;
- for ($i = 0; $i < $self->{'Num'}; $i++)
- {
- $s = $self->{'Tables'}[$i];
- if ($s->{'Platform'} == 3)
- {
- $self->{' mstable'} = $s;
- last if ($s->{'Encoding'} == 1);
- } elsif ($s->{'Platform'} == 0 || ($s->{'Platform'} == 2 && $s->{'Encoding'} == 1))
- { $self->{' mstable'} = $s; }
- }
- $self->{' mstable'};
-}
-
-
-=head2 $t->out($fh)
-
-Writes out a cmap table to a filehandle. If it has not been read, then
-just copies from input file to output
-
-=cut
-
-sub out
-{
- my ($self, $fh) = @_;
- my ($loc, $s, $i, $base_loc, $j);
-
- return $self->SUPER::out($fh) unless $self->{' read'};
-
- $base_loc = $fh->tell();
- $fh->print(pack("n2", 0, $self->{'Num'}));
-
- for ($i = 0; $i < $self->{'Num'}; $i++)
- { $fh->print(pack("nnN", $self->{'Tables'}[$i]{'Platform'}, $self->{'Tables'}[$i]{'Encoding'}, 0)); }
-
- for ($i = 0; $i < $self->{'Num'}; $i++)
- {
- $s = $self->{'Tables'}[$i];
- $s->{'val'}->tidy;
- $s->{' outloc'} = $fh->tell();
- $fh->print(pack("n3", $s->{'Format'}, 0, $s->{'Ver'})); # come back for length
- if ($s->{'Format'} == 0)
- {
- $fh->print(pack("C256", $s->{'val'}->at(0, 256)));
- } elsif ($s->{'Format'} == 6)
- {
- $fh->print(pack("n2", $s->{'Start'}, $s->{'Num'}));
- $fh->print(pack("n*", $s->{'val'}->at($s->{'Start'}, $s->{'Num'})));
- } elsif ($s->{'Format'} == 2)
- {
- } elsif ($s->{'Format'} == 4)
- {
- my ($num, $sRange, $eSel);
- my (@deltas, $delta, @range, $flat, $k, $segs, $count);
-
- $num = $#{$s->{'val'}} + 1;
- $segs = $s->{'val'};
- for ($sRange = 1, $eSel = 0; $sRange <= $num; $eSel++)
- { $sRange <<= 1;}
- $eSel--;
- $fh->print(pack("n4", $num * 2, $sRange, $eSel, ($num * 2) - $sRange));
- $fh->print(pack("n*", map {$_->{'START'} + $_->{'LEN'} - 1} @$segs));
- $fh->print(pack("n", 0));
- $fh->print(pack("n*", map {$_->{'START'}} @$segs));
-
- for ($j = 0; $j < $num; $j++)
- {
- $delta = $segs->[$j]{'VAL'}[0]; $flat = 1;
- for ($k = 1; $k < $segs->[$j]{'LEN'}; $k++)
- {
- if ($segs->[$j]{'VAL'}[$k] == 0)
- { $flat = 0; }
- if ($delta + $k != $segs->[$j]{'VAL'}[$k])
- {
- $delta = 0;
- last;
- }
- }
- push (@range, $flat);
- push (@deltas, ($delta ? $delta - $segs->[$j]{'START'} : 0));
- }
- $fh->print(pack("n*", @deltas));
-
- $count = 0;
- for ($j = 0; $j < $num; $j++)
- {
- $delta = $deltas[$j];
- if ($delta != 0 && $range[$j] == 1)
- { $range[$j] = 0; }
- else
- {
- $range[$j] = ($count + $num - $j) << 1;
- $count += $segs->[$j]{'LEN'};
- }
- }
-
- $fh->print(pack("n*", @range));
-
- for ($j = 0; $j < $num; $j++)
- {
- next if ($range[$j] == 0);
- for ($k = 0; $k < $segs->[$j]{'LEN'}; $k++)
- { $fh->print(pack("n", $segs->[$j]{'VAL'}[$k])); }
- }
- }
-
- $loc = $fh->tell();
- $fh->seek($s->{' outloc'} + 2, 0);
- $fh->print(pack("n", $loc - $s->{' outloc'}));
- $fh->seek($base_loc + 8 + ($i << 3), 0);
- $fh->print(pack("N", $s->{' outloc'} - $base_loc));
- $fh->seek($loc, 0);
- }
- $self;
-}
-
-
-=head2 @map = $t->reverse([$num])
-
-Returns a reverse map of the table of given number or the Microsoft
-cmap. I.e. given a glyph gives the Unicode value for it.
-
-=cut
-
-sub reverse
-{
- my ($self, $tnum) = @_;
- my ($table) = defined $tnum ? $self->{'Tables'}[$tnum] : $self->find_ms;
- my (@res, $i, $s, $first);
-
- foreach $s (@{$table->{'val'}})
- {
- $first = $s->{'START'};
- map {$res[$_] = $first unless $res[$_]; $first++;} @{$s->{'VAL'}};
- }
- @res;
-}
-
-1;
-
-=head1 BUGS
-
-=over 4
-
-=item *
-
-No support for format 2 tables (MBCS)
-
-=back
-
-=head1 AUTHOR
-
-Martin Hosken Martin_Hosken at sil.org. See L<Font::TTF::Font> for copyright and
-licensing.
-
-=cut
-
+package Font::TTF::OldCmap;
+
+=head1 NAME
+
+Font::TTF::OldCmap - Character map table
+
+This module is deprecated
+
+=head1 DESCRIPTION
+
+Looks after the character map. The primary structure used for handling a cmap
+is the L<Font::TTF::Segarr> which handles the segmented arrays of format 4 tables,
+and in a simpler form for format 0 tables.
+
+Due to the complexity of working with segmented arrays, most of the handling of
+such arrays is via methods rather than via instance variables.
+
+One important feature of a format 4 table is that it always contains a segment
+with a final address of 0xFFFF. If you are creating a table from scratch this is
+important (although L<Font::TTF::Segarr> can work quite happily without it).
+
+
+=head1 INSTANCE VARIABLES
+
+The instance variables listed here are not preceeded by a space due to their
+emulating structural information in the font.
+
+=over 4
+
+=item Num
+
+Number of subtables in this table
+
+=item Tables
+
+An array of subtables ([0..Num-1])
+
+=back
+
+Each subtables also has its own instance variables which are, again, not
+preceeded by a space.
+
+=over 4
+
+=item Platform
+
+The platform number for this subtable
+
+=item Encoding
+
+The encoding number for this subtable
+
+=item Format
+
+Gives the stored format of this subtable
+
+=item Ver
+
+Gives the version (or language) information for this subtable
+
+=item val
+
+This points to a L<Font::TTF::Segarr> which contains the content of the particular
+subtable.
+
+=back
+
+=head1 METHODS
+
+=cut
+
+use strict;
+use vars qw(@ISA);
+require Font::TTF::Table;
+require Font::TTF::Segarr;
+
+ at ISA = qw(Font::TTF::Table);
+
+
+=head2 $t->read
+
+Reads the cmap into memory. Format 4 subtables read the whole subtable and
+fill in the segmented array accordingly.
+
+Format 2 subtables are not read at all.
+
+=cut
+
+sub read
+{
+ my ($self) = @_;
+ my ($dat, $i, $j, $k, $id, @ids, $s);
+ my ($start, $end, $range, $delta, $form, $len, $num, $ver);
+ my ($fh) = $self->{' INFILE'};
+
+ $self->SUPER::read or return $self;
+ $fh->read($dat, 4);
+ $self->{'Num'} = unpack("x2n", $dat);
+ $self->{'Tables'} = [];
+ for ($i = 0; $i < $self->{'Num'}; $i++)
+ {
+ $s = {};
+ $fh->read($dat, 8);
+ ($s->{'Platform'}, $s->{'Encoding'}, $s->{'LOC'}) = (unpack("nnN", $dat));
+ $s->{'LOC'} += $self->{' OFFSET'};
+ push(@{$self->{'Tables'}}, $s);
+ }
+ for ($i = 0; $i < $self->{'Num'}; $i++)
+ {
+ $s = $self->{'Tables'}[$i];
+ $fh->seek($s->{'LOC'}, 0);
+ $fh->read($dat, 6);
+ ($form, $len, $ver) = (unpack("n3", $dat));
+
+ $s->{'Format'} = $form;
+ $s->{'Ver'} = $ver;
+ if ($form == 0)
+ {
+ $s->{'val'} = Font::TTF::Segarr->new;
+ $fh->read($dat, 256);
+ $s->{'val'}->fastadd_segment(0, 2, unpack("C*", $dat));
+ $s->{'Start'} = 0;
+ $s->{'Num'} = 256;
+ } elsif ($form == 6)
+ {
+ my ($start, $ecount);
+
+ $fh->read($dat, 4);
+ ($start, $ecount) = unpack("n2", $dat);
+ $fh->read($dat, $ecount << 1);
+ $s->{'val'} = Font::TTF::Segarr->new;
+ $s->{'val'}->fastadd_segment($start, 2, unpack("n*", $dat));
+ $s->{'Start'} = $start;
+ $s->{'Num'} = $ecount;
+ } elsif ($form == 2)
+ {
+# no idea what to do here yet
+ } elsif ($form == 4)
+ {
+ $fh->read($dat, 8);
+ $num = unpack("n", $dat);
+ $num >>= 1;
+ $fh->read($dat, $len - 14);
+ $s->{'val'} = Font::TTF::Segarr->new;
+ for ($j = 0; $j < $num; $j++)
+ {
+ $end = unpack("n", substr($dat, $j << 1, 2));
+ $start = unpack("n", substr($dat, ($j << 1) + ($num << 1) + 2, 2));
+ $delta = unpack("n", substr($dat, ($j << 1) + ($num << 2) + 2, 2));
+ $delta -= 65536 if $delta > 32767;
+ $range = unpack("n", substr($dat, ($j << 1) + $num * 6 + 2, 2));
+ @ids = ();
+ for ($k = $start; $k <= $end; $k++)
+ {
+ if ($range == 0)
+ { $id = $k + $delta; }
+ else
+ { $id = unpack("n", substr($dat, ($j << 1) + $num * 6 +
+ 2 + ($k - $start) * 2 + $range, 2)) + $delta; }
+ $id -= 65536 if $id > 65536;
+ push (@ids, $id);
+ }
+ $s->{'val'}->fastadd_segment($start, 0, @ids);
+ }
+ $s->{'val'}->tidy;
+ $s->{'Num'} = 0x10000; # always ends here
+ $s->{'Start'} = $s->{'val'}[0]{'START'};
+ }
+ }
+ $self;
+}
+
+
+=head2 $t->ms_lookup($uni)
+
+Given a Unicode value in the MS table (Platform 3, Encoding 1) locates that
+table and looks up the appropriate glyph number from it.
+
+=cut
+
+sub ms_lookup
+{
+ my ($self, $uni) = @_;
+
+ $self->find_ms || return undef unless (defined $self->{' mstable'});
+ return $self->{' mstable'}{'val'}->at($uni);
+}
+
+
+=head2 $t->find_ms
+
+Finds the Microsoft Unicode table and sets the C<mstable> instance variable
+to it if found. Returns the table it finds.
+
+=cut
+sub find_ms
+{
+ my ($self) = @_;
+ my ($i, $s, $alt);
+
+ return $self->{' mstable'} if defined $self->{' mstable'};
+ $self->read;
+ for ($i = 0; $i < $self->{'Num'}; $i++)
+ {
+ $s = $self->{'Tables'}[$i];
+ if ($s->{'Platform'} == 3)
+ {
+ $self->{' mstable'} = $s;
+ last if ($s->{'Encoding'} == 1);
+ } elsif ($s->{'Platform'} == 0 || ($s->{'Platform'} == 2 && $s->{'Encoding'} == 1))
+ { $self->{' mstable'} = $s; }
+ }
+ $self->{' mstable'};
+}
+
+
+=head2 $t->out($fh)
+
+Writes out a cmap table to a filehandle. If it has not been read, then
+just copies from input file to output
+
+=cut
+
+sub out
+{
+ my ($self, $fh) = @_;
+ my ($loc, $s, $i, $base_loc, $j);
+
+ return $self->SUPER::out($fh) unless $self->{' read'};
+
+ $base_loc = $fh->tell();
+ $fh->print(pack("n2", 0, $self->{'Num'}));
+
+ for ($i = 0; $i < $self->{'Num'}; $i++)
+ { $fh->print(pack("nnN", $self->{'Tables'}[$i]{'Platform'}, $self->{'Tables'}[$i]{'Encoding'}, 0)); }
+
+ for ($i = 0; $i < $self->{'Num'}; $i++)
+ {
+ $s = $self->{'Tables'}[$i];
+ $s->{'val'}->tidy;
+ $s->{' outloc'} = $fh->tell();
+ $fh->print(pack("n3", $s->{'Format'}, 0, $s->{'Ver'})); # come back for length
+ if ($s->{'Format'} == 0)
+ {
+ $fh->print(pack("C256", $s->{'val'}->at(0, 256)));
+ } elsif ($s->{'Format'} == 6)
+ {
+ $fh->print(pack("n2", $s->{'Start'}, $s->{'Num'}));
+ $fh->print(pack("n*", $s->{'val'}->at($s->{'Start'}, $s->{'Num'})));
+ } elsif ($s->{'Format'} == 2)
+ {
+ } elsif ($s->{'Format'} == 4)
+ {
+ my ($num, $sRange, $eSel);
+ my (@deltas, $delta, @range, $flat, $k, $segs, $count);
+
+ $num = $#{$s->{'val'}} + 1;
+ $segs = $s->{'val'};
+ for ($sRange = 1, $eSel = 0; $sRange <= $num; $eSel++)
+ { $sRange <<= 1;}
+ $eSel--;
+ $fh->print(pack("n4", $num * 2, $sRange, $eSel, ($num * 2) - $sRange));
+ $fh->print(pack("n*", map {$_->{'START'} + $_->{'LEN'} - 1} @$segs));
+ $fh->print(pack("n", 0));
+ $fh->print(pack("n*", map {$_->{'START'}} @$segs));
+
+ for ($j = 0; $j < $num; $j++)
+ {
+ $delta = $segs->[$j]{'VAL'}[0]; $flat = 1;
+ for ($k = 1; $k < $segs->[$j]{'LEN'}; $k++)
+ {
+ if ($segs->[$j]{'VAL'}[$k] == 0)
+ { $flat = 0; }
+ if ($delta + $k != $segs->[$j]{'VAL'}[$k])
+ {
+ $delta = 0;
+ last;
+ }
+ }
+ push (@range, $flat);
+ push (@deltas, ($delta ? $delta - $segs->[$j]{'START'} : 0));
+ }
+ $fh->print(pack("n*", @deltas));
+
+ $count = 0;
+ for ($j = 0; $j < $num; $j++)
+ {
+ $delta = $deltas[$j];
+ if ($delta != 0 && $range[$j] == 1)
+ { $range[$j] = 0; }
+ else
+ {
+ $range[$j] = ($count + $num - $j) << 1;
+ $count += $segs->[$j]{'LEN'};
+ }
+ }
+
+ $fh->print(pack("n*", @range));
+
+ for ($j = 0; $j < $num; $j++)
+ {
+ next if ($range[$j] == 0);
+ for ($k = 0; $k < $segs->[$j]{'LEN'}; $k++)
+ { $fh->print(pack("n", $segs->[$j]{'VAL'}[$k])); }
+ }
+ }
+
+ $loc = $fh->tell();
+ $fh->seek($s->{' outloc'} + 2, 0);
+ $fh->print(pack("n", $loc - $s->{' outloc'}));
+ $fh->seek($base_loc + 8 + ($i << 3), 0);
+ $fh->print(pack("N", $s->{' outloc'} - $base_loc));
+ $fh->seek($loc, 0);
+ }
+ $self;
+}
+
+
+=head2 @map = $t->reverse([$num])
+
+Returns a reverse map of the table of given number or the Microsoft
+cmap. I.e. given a glyph gives the Unicode value for it.
+
+=cut
+
+sub reverse
+{
+ my ($self, $tnum) = @_;
+ my ($table) = defined $tnum ? $self->{'Tables'}[$tnum] : $self->find_ms;
+ my (@res, $i, $s, $first);
+
+ foreach $s (@{$table->{'val'}})
+ {
+ $first = $s->{'START'};
+ map {$res[$_] = $first unless $res[$_]; $first++;} @{$s->{'VAL'}};
+ }
+ @res;
+}
+
+1;
+
+=head1 BUGS
+
+=over 4
+
+=item *
+
+No support for format 2 tables (MBCS)
+
+=back
+
+=head1 AUTHOR
+
+Martin Hosken Martin_Hosken at sil.org. See L<Font::TTF::Font> for copyright and
+licensing.
+
+=cut
+
Modified: packages/libfont-ttf-perl/trunk/lib/Font/TTF/OldMort.pm
===================================================================
--- packages/libfont-ttf-perl/trunk/lib/Font/TTF/OldMort.pm 2006-01-17 02:56:43 UTC (rev 1966)
+++ packages/libfont-ttf-perl/trunk/lib/Font/TTF/OldMort.pm 2006-01-17 03:07:20 UTC (rev 1967)
@@ -1,705 +1,706 @@
-package Font::TTF::OldMort;
-
-=head1 NAME
-
-Font::TTF::OldMort - Glyph Metamorphosis table in a font
-
-=head1 DESCRIPTION
-
-=head1 INSTANCE VARIABLES
-
-=item version
-
-table version number (Fixed: currently 1.0)
-
-=item chains
-
-list of metamorphosis chains, each of which has its own fields:
-
-=over
-
-=item defaultFlags
-
-chain's default subfeature flags (UInt32)
-
-=item featureEntries
-
-list of feature entries, each of which has fields:
-
-=over
-
-=item type
-
-=item setting
-
-=item enable
-
-=item disable
-
-=back
-
-=item subtables
-
-list of metamorphosis subtables, each of which has fields:
-
-=over
-
-=item type
-
-subtable type (0: rearrangement; 1: contextual substitution; 2: ligature;
-4: non-contextual substitution; 5: insertion)
-
-=item direction
-
-processing direction ('LR' or 'RL')
-
-=item orientation
-
-applies to text in which orientation ('VH', 'V', or 'H')
-
-=item subFeatureFlags
-
-the subfeature flags controlling whether the table is used (UInt32)
-
-=back
-
-Further fields depend on the type of subtable:
-
-=over
-
-Rearrangement table:
-
-=over
-
-=item classes
-
-array of lists of glyphs
-
-=item states
-
-array of arrays of hashes{'nextState', 'flags'}
-
-=back
-
-Contextual substitution table:
-
-=over
-
-=item classes
-
-array of lists of glyphs
-
-=item states
-
-array of array of hashes{'nextState', 'flags', 'actions'}, where C<actions>
-is an array of two elements which are offsets to be added to [marked, current]
-glyph to get index into C<mappings> (or C<undef> if no mapping to be applied)
-
-=item mappings
-
-list of glyph codes mapped to through the state table mappings
-
-=back
-
-Ligature table:
-
-Non-contextual substitution table:
-
-Insertion table:
-
-=back
-
-=back
-
-=head1 METHODS
-
-=cut
-
-use strict;
-use vars qw(@ISA);
-use Font::TTF::Utils;
-use Font::TTF::AATutils;
-
- at ISA = qw(Font::TTF::Table);
-
-=head2 $t->read
-
-Reads the table into memory
-
-=cut
-
-sub read
-{
- my ($self) = @_;
- my ($dat, $fh, $numChains);
-
- $self->SUPER::read or return $self;
-
- $fh = $self->{' INFILE'};
-
- $fh->read($dat, 8);
- ($self->{'version'}, $numChains) = TTF_Unpack("fL", $dat);
-
- my $chains = [];
- foreach (1 .. $numChains) {
- my $chainStart = $fh->tell();
- $fh->read($dat, 12);
- my ($defaultFlags, $chainLength, $nFeatureEntries, $nSubtables) = TTF_Unpack("LLSS", $dat);
- my $featureEntries = [];
- foreach (1 .. $nFeatureEntries) {
- $fh->read($dat, 12);
- my ($featureType, $featureSetting, $enableFlags, $disableFlags) = TTF_Unpack("SSLL", $dat);
- push @$featureEntries, {
- 'type' => $featureType,
- 'setting' => $featureSetting,
- 'enable' => $enableFlags,
- 'disable' => $disableFlags
- };
- }
- my $subtables = [];
- foreach (1 .. $nSubtables) {
- my $subtableStart = $fh->tell();
- $fh->read($dat, 8);
- my ($length, $coverage, $subFeatureFlags) = TTF_Unpack("SSL", $dat);
- my $type = $coverage & 0x0007;
-
- my $subtable = {
- 'type' => $type,
- 'direction' => (($coverage & 0x4000) ? 'RL' : 'LR'),
- 'orientation' => (($coverage & 0x2000) ? 'VH' : ($coverage & 0x8000) ? 'V' : 'H'),
- 'subFeatureFlags' => $subFeatureFlags
- };
-
- if ($type == 0) { # rearrangement
- my ($classes, $states) = AAT_read_state_table($fh, 0);
- $subtable->{'classes'} = $classes;
- $subtable->{'states'} = $states;
- }
-
- elsif ($type == 1) { # contextual
- my $stateTableStart = $fh->tell();
- my ($classes, $states, $entries) = AAT_read_state_table($fh, 2);
-
- $fh->seek($stateTableStart, IO::File::SEEK_SET);
- $fh->read($dat, 10);
- my ($stateSize, $classTable, $stateArray, $entryTable, $mappingTables) = unpack("nnnnn", $dat);
- my $limits = [$classTable, $stateArray, $entryTable, $mappingTables, $length - 8];
-
- foreach (@$entries) {
- my $actions = $_->{'actions'};
- foreach (@$actions) {
- $_ = $_ ? $_ - ($mappingTables / 2) : undef;
- }
- }
-
- $subtable->{'classes'} = $classes;
- $subtable->{'states'} = $states;
- $subtable->{'mappings'} = [unpack("n*", AAT_read_subtable($fh, $stateTableStart, $mappingTables, $limits))];
- }
-
- elsif ($type == 2) { # ligature
- my $stateTableStart = $fh->tell();
- my ($classes, $states, $entries) = AAT_read_state_table($fh, 0);
-
- $fh->seek($stateTableStart, IO::File::SEEK_SET);
- $fh->read($dat, 14);
- my ($stateSize, $classTable, $stateArray, $entryTable,
- $ligActionTable, $componentTable, $ligatureTable) = unpack("nnnnnnn", $dat);
- my $limits = [$classTable, $stateArray, $entryTable, $ligActionTable, $componentTable, $ligatureTable, $length - 8];
-
- my %actions;
- my $actionLists;
- foreach (@$entries) {
- my $offset = $_->{'flags'} & 0x3fff;
- $_->{'flags'} &= ~0x3fff;
- if ($offset != 0) {
- if (not defined $actions{$offset}) {
- $fh->seek($stateTableStart + $offset, IO::File::SEEK_SET);
- my $actionList;
- while (1) {
- $fh->read($dat, 4);
- my $action = unpack("N", $dat);
- my ($last, $store, $component) = (($action & 0x80000000) != 0, ($action & 0xC0000000) != 0, ($action & 0x3fffffff));
- $component -= 0x40000000 if $component > 0x1fffffff;
- $component -= $componentTable / 2;
- push @$actionList, { 'store' => $store, 'component' => $component };
- last if $last;
- }
- push @$actionLists, $actionList;
- $actions{$offset} = $#$actionLists;
- }
- $_->{'actions'} = $actions{$offset};
- }
- }
-
- $subtable->{'componentTable'} = $componentTable;
- my $components = [unpack("n*", AAT_read_subtable($fh, $stateTableStart, $componentTable, $limits))];
- foreach (@$components) {
- $_ = ($_ - $ligatureTable) . " +" if $_ >= $ligatureTable;
- }
- $subtable->{'components'} = $components;
-
- $subtable->{'ligatureTable'} = $ligatureTable;
- $subtable->{'ligatures'} = [unpack("n*", AAT_read_subtable($fh, $stateTableStart, $ligatureTable, $limits))];
-
- $subtable->{'classes'} = $classes;
- $subtable->{'states'} = $states;
- $subtable->{'actionLists'} = $actionLists;
- }
-
- elsif ($type == 4) { # non-contextual
- my ($format, $lookup) = AAT_read_lookup($fh, 2, $length - 8, undef);
- $subtable->{'format'} = $format;
- $subtable->{'lookup'} = $lookup;
- }
-
- elsif ($type == 5) { # insertion
- my $stateTableStart = $fh->tell();
- my ($classes, $states, $entries) = AAT_read_state_table($fh, 2);
-
- my %insertListHash;
- my $insertLists;
- foreach (@$entries) {
- my $flags = $_->{'flags'};
- my @insertCount = (($flags & 0x03e0) >> 5, ($flags & 0x001f));
- my $actions = $_->{'actions'};
- foreach (0 .. 1) {
- if ($insertCount[$_] > 0) {
- $fh->seek($stateTableStart + $actions->[$_], IO::File::SEEK_SET);
- $fh->read($dat, $insertCount[$_] * 2);
- if (not defined $insertListHash{$dat}) {
- push @$insertLists, [unpack("n*", $dat)];
- $insertListHash{$dat} = $#$insertLists;
- }
- $actions->[$_] = $insertListHash{$dat};
- }
- else {
- $actions->[$_] = undef;
- }
- }
- }
-
- $subtable->{'classes'} = $classes;
- $subtable->{'states'} = $states;
- $subtable->{'insertLists'} = $insertLists;
- }
-
- else {
- die "unknown subtable type";
- }
-
- push @$subtables, $subtable;
- $fh->seek($subtableStart + $length, IO::File::SEEK_SET);
- }
-
- push @$chains, {
- 'defaultFlags' => $defaultFlags,
- 'featureEntries' => $featureEntries,
- 'subtables' => $subtables
- };
- $fh->seek($chainStart + $chainLength, IO::File::SEEK_SET);
- }
-
- $self->{'chains'} = $chains;
-
- $self;
-}
-
-=head2 $t->out($fh)
-
-Writes the table to a file either from memory or by copying
-
-=cut
-
-sub out
-{
- my ($self, $fh) = @_;
-
- return $self->SUPER::out($fh) unless $self->{' read'};
-
- my $chains = $self->{'chains'};
- $fh->print(TTF_Pack("fL", $self->{'version'}, scalar @$chains));
-
- foreach (@$chains) {
- my $chainStart = $fh->tell();
- my ($featureEntries, $subtables) = ($_->{'featureEntries'}, $_->{'subtables'});
- $fh->print(TTF_Pack("LLSS", $_->{'defaultFlags'}, 0, scalar @$featureEntries, scalar @$subtables)); # placeholder for length
-
- foreach (@$featureEntries) {
- $fh->print(TTF_Pack("SSLL", $_->{'type'}, $_->{'setting'}, $_->{'enable'}, $_->{'disable'}));
- }
-
- foreach (@$subtables) {
- my $subtableStart = $fh->tell();
- my $type = $_->{'type'};
- my $coverage = $type;
- $coverage += 0x4000 if $_->{'direction'} eq 'RL';
- $coverage += 0x2000 if $_->{'orientation'} eq 'VH';
- $coverage += 0x8000 if $_->{'orientation'} eq 'V';
-
- $fh->print(TTF_Pack("SSL", 0, $coverage, $_->{'subFeatureFlags'})); # placeholder for length
-
- if ($type == 0) { # rearrangement
- AAT_write_state_table($fh, $_->{'classes'}, $_->{'states'}, 0);
- }
-
- elsif ($type == 1) { # contextual
- my $stHeader = $fh->tell();
- $fh->print(pack("nnnnn", (0) x 5)); # placeholders for stateSize, classTable, stateArray, entryTable, mappingTables
-
- my $classTable = $fh->tell() - $stHeader;
- my $classes = $_->{'classes'};
- AAT_write_classes($fh, $classes);
-
- my $stateArray = $fh->tell() - $stHeader;
- my $states = $_->{'states'};
- my ($stateSize, $entries) = AAT_write_states($fh, $classes, $stateArray, $states,
- sub {
- my $actions = $_->{'actions'};
- ( $_->{'flags'}, @$actions )
- }
- );
-
- my $entryTable = $fh->tell() - $stHeader;
- my $offset = ($entryTable + 8 * @$entries) / 2;
- foreach (@$entries) {
- my ($nextState, $flags, @parts) = split /,/;
- $fh->print(pack("nnnn", $nextState, $flags, map { $_ eq "" ? 0 : $_ + $offset } @parts));
- }
-
- my $mappingTables = $fh->tell() - $stHeader;
- my $mappings = $_->{'mappings'};
- $fh->print(pack("n*", @$mappings));
-
- my $loc = $fh->tell();
- $fh->seek($stHeader, IO::File::SEEK_SET);
- $fh->print(pack("nnnnn", $stateSize, $classTable, $stateArray, $entryTable, $mappingTables));
- $fh->seek($loc, IO::File::SEEK_SET);
- }
-
- elsif ($type == 2) { # ligature
- my $stHeader = $fh->tell();
- $fh->print(pack("nnnnnnn", (0) x 7)); # placeholders for stateSize, classTable, stateArray, entryTable, actionLists, components, ligatures
-
- my $classTable = $fh->tell() - $stHeader;
- my $classes = $_->{'classes'};
- AAT_write_classes($fh, $classes);
-
- my $stateArray = $fh->tell() - $stHeader;
- my $states = $_->{'states'};
-
- my ($stateSize, $entries) = AAT_write_states($fh, $classes, $stateArray, $states,
- sub {
- ( $_->{'flags'} & 0xc000, $_->{'actions'} )
- }
- );
-
- my $actionLists = $_->{'actionLists'};
- my %actionListOffset;
- my $actionListDataLength = 0;
- my @actionListEntries;
- foreach (0 .. $#$entries) {
- my ($nextState, $flags, $offset) = split(/,/, $entries->[$_]);
- if ($offset eq "") {
- $offset = undef;
- }
- else {
- if (defined $actionListOffset{$offset}) {
- $offset = $actionListOffset{$offset};
- }
- else {
- $actionListOffset{$offset} = $actionListDataLength;
- my $list = $actionLists->[$offset];
- $actionListDataLength += 4 * @$list;
- push @actionListEntries, $list;
- $offset = $actionListOffset{$offset};
- }
- }
- $entries->[$_] = [ $nextState, $flags, $offset ];
- }
- my $entryTable = $fh->tell() - $stHeader;
- my $ligActionLists = ($entryTable + @$entries * 4 + 3) & ~3;
- foreach (@$entries) {
- $_->[2] += $ligActionLists if defined $_->[2];
- $fh->print(pack("nn", $_->[0], $_->[1] + $_->[2]));
- }
- $fh->print(pack("C*", (0) x ($ligActionLists - $entryTable - @$entries * 4)));
-
- die "internal error" if $fh->tell() != $ligActionLists + $stHeader;
-
- my $componentTable = $fh->tell() - $stHeader + $actionListDataLength;
- my $actionList;
- foreach $actionList (@actionListEntries) {
- foreach (0 .. $#$actionList) {
- my $action = $actionList->[$_];
- my $val = $action->{'component'} + $componentTable / 2;
- $val += 0x40000000 if $val < 0;
- $val &= 0x3fffffff;
- $val |= 0x40000000 if $action->{'store'};
- $val |= 0x80000000 if $_ == $#$actionList;
- $fh->print(pack("N", $val));
- }
- }
-
- die "internal error" if $fh->tell() != $componentTable + $stHeader;
-
- my $components = $_->{'components'};
- my $ligatureTable = $componentTable + @$components * 2;
- $fh->print(pack("n*", map { (index($_, '+') >= 0 ? $ligatureTable : 0) + $_ } @$components));
-
- my $ligatures = $_->{'ligatures'};
- $fh->print(pack("n*", @$ligatures));
-
- my $loc = $fh->tell();
- $fh->seek($stHeader, IO::File::SEEK_SET);
- $fh->print(pack("nnnnnnn", $stateSize, $classTable, $stateArray, $entryTable, $ligActionLists, $componentTable, $ligatureTable));
- $fh->seek($loc, IO::File::SEEK_SET);
- }
-
- elsif ($type == 4) { # non-contextual
- AAT_write_lookup($fh, $_->{'format'}, $_->{'lookup'}, 2, undef);
- }
-
- elsif ($type == 5) { # insertion
- }
-
- else {
- die "unknown subtable type";
- }
-
- my $length = $fh->tell() - $subtableStart;
- my $padBytes = (4 - ($length & 3)) & 3;
- $fh->print(pack("C*", (0) x $padBytes));
- $length += $padBytes;
- $fh->seek($subtableStart, IO::File::SEEK_SET);
- $fh->print(pack("n", $length));
- $fh->seek($subtableStart + $length, IO::File::SEEK_SET);
- }
-
- my $chainLength = $fh->tell() - $chainStart;
- $fh->seek($chainStart + 4, IO::File::SEEK_SET);
- $fh->print(pack("N", $chainLength));
- $fh->seek($chainStart + $chainLength, IO::File::SEEK_SET);
- }
-}
-
-=head2 $t->print($fh)
-
-Prints a human-readable representation of the table
-
-=cut
-
-sub print
-{
- my ($self, $fh) = @_;
-
- $self->read;
- my $feat = $self->{' PARENT'}->{'feat'};
- $feat->read;
- my $post = $self->{' PARENT'}->{'post'};
- $post->read;
-
- $fh = 'STDOUT' unless defined $fh;
-
- $fh->printf("version %f\n", $self->{'version'});
-
- my $chains = $self->{'chains'};
- foreach (@$chains) {
- my $defaultFlags = $_->{'defaultFlags'};
- $fh->printf("chain: defaultFlags = %08x\n", $defaultFlags);
-
- my $featureEntries = $_->{'featureEntries'};
- foreach (@$featureEntries) {
- $fh->printf("\tfeature %d, setting %d : enableFlags = %08x, disableFlags = %08x # '%s: %s'\n",
- $_->{'type'}, $_->{'setting'}, $_->{'enable'}, $_->{'disable'},
- $feat->settingName($_->{'type'}, $_->{'setting'}));
- }
-
- my $subtables = $_->{'subtables'};
- foreach (@$subtables) {
- my $type = $_->{'type'};
- my $subFeatureFlags = $_->{'subFeatureFlags'};
- $fh->printf("\n\t%s table, %s, %s, subFeatureFlags = %08x # %s (%s)\n",
- subtable_type_($type), $_->{'direction'}, $_->{'orientation'}, $subFeatureFlags,
- "Default " . ((($subFeatureFlags & $defaultFlags) != 0) ? "On" : "Off"),
- join(", ",
- map {
- join(": ", $feat->settingName($_->{'type'}, $_->{'setting'}) )
- } grep { ($_->{'enable'} & $subFeatureFlags) != 0 } @$featureEntries
- ) );
-
- if ($type == 0) { # rearrangement
- print_classes_($fh, $_, $post);
-
- $fh->print("\n");
- my $states = $_->{'states'};
- my @verbs = ( "0", "Ax->xA", "xD->Dx", "AxD->DxA",
- "ABx->xAB", "ABx->xBA", "xCD->CDx", "xCD->DCx",
- "AxCD->CDxA", "AxCD->DCxA", "ABxD->DxAB", "ABxD->DxBA",
- "ABxCD->CDxAB", "ABxCD->CDxBA", "ABxCD->DCxAB", "ABxCD->DCxBA");
- foreach (0 .. $#$states) {
- $fh->printf("\t\tState %d:", $_);
- my $state = $states->[$_];
- foreach (@$state) {
- my $flags;
- $flags .= "!" if ($_->{'flags'} & 0x4000);
- $flags .= "<" if ($_->{'flags'} & 0x8000);
- $flags .= ">" if ($_->{'flags'} & 0x2000);
- $fh->printf("\t(%s%d,%s)", $flags, $_->{'nextState'}, $verbs[($_->{'flags'} & 0x000f)]);
- }
- $fh->print("\n");
- }
- }
-
- elsif ($type == 1) { # contextual
- print_classes_($fh, $_, $post);
-
- $fh->print("\n");
- my $states = $_->{'states'};
- foreach (0 .. $#$states) {
- $fh->printf("\t\tState %d:", $_);
- my $state = $states->[$_];
- foreach (@$state) {
- my $flags;
- $flags .= "!" if ($_->{'flags'} & 0x4000);
- $flags .= "*" if ($_->{'flags'} & 0x8000);
- my $actions = $_->{'actions'};
- $fh->printf("\t(%s%d,%s,%s)", $flags, $_->{'nextState'}, map { defined $_ ? $_ : "=" } @$actions);
- }
- $fh->print("\n");
- }
-
- $fh->print("\n");
- my $mappings = $_->{'mappings'};
- foreach (0 .. $#$mappings) {
- $fh->printf("\t\tMapping %d: %d [%s]\n", $_, $mappings->[$_], $post->{'VAL'}[$mappings->[$_]]);
- }
- }
-
- elsif ($type == 2) { # ligature
- print_classes_($fh, $_, $post);
-
- $fh->print("\n");
- my $states = $_->{'states'};
- foreach (0 .. $#$states) {
- $fh->printf("\t\tState %d:", $_);
- my $state = $states->[$_];
- foreach (@$state) {
- my $flags;
- $flags .= "!" if ($_->{'flags'} & 0x4000);
- $flags .= "*" if ($_->{'flags'} & 0x8000);
- $fh->printf("\t(%s%d,%s)", $flags, $_->{'nextState'}, defined $_->{'actions'} ? $_->{'actions'} : "=");
- }
- $fh->print("\n");
- }
-
- $fh->print("\n");
- my $actionLists = $_->{'actionLists'};
- foreach (0 .. $#$actionLists) {
- $fh->printf("\t\tList %d:\t", $_);
- my $actionList = $actionLists->[$_];
- $fh->printf("%s\n", join(", ", map { ($_->{'component'} . ($_->{'store'} ? "*" : "") ) } @$actionList));
- }
-
- my $ligatureTable = $_->{'ligatureTable'};
-
- $fh->print("\n");
- my $components = $_->{'components'};
- foreach (0 .. $#$components) {
- $fh->printf("\t\tComponent %d: %s\n", $_, $components->[$_]);
- }
-
- $fh->print("\n");
- my $ligatures = $_->{'ligatures'};
- foreach (0 .. $#$ligatures) {
- $fh->printf("\t\tLigature %d: %d [%s]\n", $_, $ligatures->[$_], $post->{'VAL'}[$ligatures->[$_]]);
- }
- }
-
- elsif ($type == 4) { # non-contextual
- my $lookup = $_->{'lookup'};
- $fh->printf("\t\tLookup format %d\n", $_->{'format'});
- if (defined $lookup) {
- foreach (sort { $a <=> $b } keys %$lookup) {
- $fh->printf("\t\t\t%d [%s] -> %d [%s])\n", $_, $post->{'VAL'}[$_], $lookup->{$_}, $post->{'VAL'}[$lookup->{$_}]);
- }
- }
- }
-
- elsif ($type == 5) { # insertion
- print_classes_($fh, $_, $post);
-
- $fh->print("\n");
- my $states = $_->{'states'};
- foreach (0 .. $#$states) {
- $fh->printf("\t\tState %d:", $_);
- my $state = $states->[$_];
- foreach (@$state) {
- my $flags;
- $flags .= "!" if ($_->{'flags'} & 0x4000);
- $flags .= "*" if ($_->{'flags'} & 0x8000);
- my $actions = $_->{'actions'};
- $fh->printf("\t(%s%d,%s,%s)", $flags, $_->{'nextState'}, map { defined $_ ? $_ : "=" } @$actions);
- }
- $fh->print("\n");
- }
-
- $fh->print("\n");
- my $insertLists = $_->{'insertLists'};
- foreach (0 .. $#$insertLists) {
- my $insertList = $insertLists->[$_];
- $fh->printf("\t\tList %d: %s\n", $_, join(", ", map { $_ . " [" . $post->{'VAL'}[$_] . "]" } @$insertList));
- }
- }
-
- else {
- # unknown
- }
- }
- }
-}
-
-sub print_classes_
-{
- my ($fh, $subtable, $post) = @_;
-
- my $classes = $subtable->{'classes'};
- foreach (0 .. $#$classes) {
- my $class = $classes->[$_];
- if (defined $class) {
- $fh->printf("\t\tClass %d:\t%s\n", $_, join(", ", map { $_ . " [" . $post->{'VAL'}[$_] . "]" } @$class));
- }
- }
-}
-
-sub subtable_type_
-{
- my ($val) = @_;
- my ($res);
-
- my @types = (
- 'Rearrangement',
- 'Contextual',
- 'Ligature',
- undef,
- 'Non-contextual',
- 'Insertion',
- );
- $res = $types[$val] or ('Undefined (' . $val . ')');
-
- $res;
-}
-
-1;
-
-=head1 BUGS
-
-None known
-
-=head1 AUTHOR
-
-Jonathan Kew L<Jonathan_Kew at sil.org>. See L<Font::TTF::Font> for copyright and
-licensing.
-
-=cut
-
+package Font::TTF::OldMort;
+
+=head1 NAME
+
+Font::TTF::OldMort - Glyph Metamorphosis table in a font
+
+=head1 DESCRIPTION
+
+=head1 INSTANCE VARIABLES
+
+=item version
+
+table version number (Fixed: currently 1.0)
+
+=item chains
+
+list of metamorphosis chains, each of which has its own fields:
+
+=over
+
+=item defaultFlags
+
+chain's default subfeature flags (UInt32)
+
+=item featureEntries
+
+list of feature entries, each of which has fields:
+
+=over
+
+=item type
+
+=item setting
+
+=item enable
+
+=item disable
+
+=back
+
+=item subtables
+
+list of metamorphosis subtables, each of which has fields:
+
+=over
+
+=item type
+
+subtable type (0: rearrangement; 1: contextual substitution; 2: ligature;
+4: non-contextual substitution; 5: insertion)
+
+=item direction
+
+processing direction ('LR' or 'RL')
+
+=item orientation
+
+applies to text in which orientation ('VH', 'V', or 'H')
+
+=item subFeatureFlags
+
+the subfeature flags controlling whether the table is used (UInt32)
+
+=back
+
+Further fields depend on the type of subtable:
+
+=over
+
+Rearrangement table:
+
+=over
+
+=item classes
+
+array of lists of glyphs
+
+=item states
+
+array of arrays of hashes{'nextState', 'flags'}
+
+=back
+
+Contextual substitution table:
+
+=over
+
+=item classes
+
+array of lists of glyphs
+
+=item states
+
+array of array of hashes{'nextState', 'flags', 'actions'}, where C<actions>
+is an array of two elements which are offsets to be added to [marked, current]
+glyph to get index into C<mappings> (or C<undef> if no mapping to be applied)
+
+=item mappings
+
+list of glyph codes mapped to through the state table mappings
+
+=back
+
+Ligature table:
+
+Non-contextual substitution table:
+
+Insertion table:
+
+=back
+
+=back
+
+=head1 METHODS
+
+=cut
+
+use strict;
+use vars qw(@ISA);
+use Font::TTF::Utils;
+use Font::TTF::AATutils;
+use IO::File;
+
+ at ISA = qw(Font::TTF::Table);
+
+=head2 $t->read
+
+Reads the table into memory
+
+=cut
+
+sub read
+{
+ my ($self) = @_;
+ my ($dat, $fh, $numChains);
+
+ $self->SUPER::read or return $self;
+
+ $fh = $self->{' INFILE'};
+
+ $fh->read($dat, 8);
+ ($self->{'version'}, $numChains) = TTF_Unpack("fL", $dat);
+
+ my $chains = [];
+ foreach (1 .. $numChains) {
+ my $chainStart = $fh->tell();
+ $fh->read($dat, 12);
+ my ($defaultFlags, $chainLength, $nFeatureEntries, $nSubtables) = TTF_Unpack("LLSS", $dat);
+ my $featureEntries = [];
+ foreach (1 .. $nFeatureEntries) {
+ $fh->read($dat, 12);
+ my ($featureType, $featureSetting, $enableFlags, $disableFlags) = TTF_Unpack("SSLL", $dat);
+ push @$featureEntries, {
+ 'type' => $featureType,
+ 'setting' => $featureSetting,
+ 'enable' => $enableFlags,
+ 'disable' => $disableFlags
+ };
+ }
+ my $subtables = [];
+ foreach (1 .. $nSubtables) {
+ my $subtableStart = $fh->tell();
+ $fh->read($dat, 8);
+ my ($length, $coverage, $subFeatureFlags) = TTF_Unpack("SSL", $dat);
+ my $type = $coverage & 0x0007;
+
+ my $subtable = {
+ 'type' => $type,
+ 'direction' => (($coverage & 0x4000) ? 'RL' : 'LR'),
+ 'orientation' => (($coverage & 0x2000) ? 'VH' : ($coverage & 0x8000) ? 'V' : 'H'),
+ 'subFeatureFlags' => $subFeatureFlags
+ };
+
+ if ($type == 0) { # rearrangement
+ my ($classes, $states) = AAT_read_state_table($fh, 0);
+ $subtable->{'classes'} = $classes;
+ $subtable->{'states'} = $states;
+ }
+
+ elsif ($type == 1) { # contextual
+ my $stateTableStart = $fh->tell();
+ my ($classes, $states, $entries) = AAT_read_state_table($fh, 2);
+
+ $fh->seek($stateTableStart, IO::File::SEEK_SET);
+ $fh->read($dat, 10);
+ my ($stateSize, $classTable, $stateArray, $entryTable, $mappingTables) = unpack("nnnnn", $dat);
+ my $limits = [$classTable, $stateArray, $entryTable, $mappingTables, $length - 8];
+
+ foreach (@$entries) {
+ my $actions = $_->{'actions'};
+ foreach (@$actions) {
+ $_ = $_ ? $_ - ($mappingTables / 2) : undef;
+ }
+ }
+
+ $subtable->{'classes'} = $classes;
+ $subtable->{'states'} = $states;
+ $subtable->{'mappings'} = [unpack("n*", AAT_read_subtable($fh, $stateTableStart, $mappingTables, $limits))];
+ }
+
+ elsif ($type == 2) { # ligature
+ my $stateTableStart = $fh->tell();
+ my ($classes, $states, $entries) = AAT_read_state_table($fh, 0);
+
+ $fh->seek($stateTableStart, IO::File::SEEK_SET);
+ $fh->read($dat, 14);
+ my ($stateSize, $classTable, $stateArray, $entryTable,
+ $ligActionTable, $componentTable, $ligatureTable) = unpack("nnnnnnn", $dat);
+ my $limits = [$classTable, $stateArray, $entryTable, $ligActionTable, $componentTable, $ligatureTable, $length - 8];
+
+ my %actions;
+ my $actionLists;
+ foreach (@$entries) {
+ my $offset = $_->{'flags'} & 0x3fff;
+ $_->{'flags'} &= ~0x3fff;
+ if ($offset != 0) {
+ if (not defined $actions{$offset}) {
+ $fh->seek($stateTableStart + $offset, IO::File::SEEK_SET);
+ my $actionList;
+ while (1) {
+ $fh->read($dat, 4);
+ my $action = unpack("N", $dat);
+ my ($last, $store, $component) = (($action & 0x80000000) != 0, ($action & 0xC0000000) != 0, ($action & 0x3fffffff));
+ $component -= 0x40000000 if $component > 0x1fffffff;
+ $component -= $componentTable / 2;
+ push @$actionList, { 'store' => $store, 'component' => $component };
+ last if $last;
+ }
+ push @$actionLists, $actionList;
+ $actions{$offset} = $#$actionLists;
+ }
+ $_->{'actions'} = $actions{$offset};
+ }
+ }
+
+ $subtable->{'componentTable'} = $componentTable;
+ my $components = [unpack("n*", AAT_read_subtable($fh, $stateTableStart, $componentTable, $limits))];
+ foreach (@$components) {
+ $_ = ($_ - $ligatureTable) . " +" if $_ >= $ligatureTable;
+ }
+ $subtable->{'components'} = $components;
+
+ $subtable->{'ligatureTable'} = $ligatureTable;
+ $subtable->{'ligatures'} = [unpack("n*", AAT_read_subtable($fh, $stateTableStart, $ligatureTable, $limits))];
+
+ $subtable->{'classes'} = $classes;
+ $subtable->{'states'} = $states;
+ $subtable->{'actionLists'} = $actionLists;
+ }
+
+ elsif ($type == 4) { # non-contextual
+ my ($format, $lookup) = AAT_read_lookup($fh, 2, $length - 8, undef);
+ $subtable->{'format'} = $format;
+ $subtable->{'lookup'} = $lookup;
+ }
+
+ elsif ($type == 5) { # insertion
+ my $stateTableStart = $fh->tell();
+ my ($classes, $states, $entries) = AAT_read_state_table($fh, 2);
+
+ my %insertListHash;
+ my $insertLists;
+ foreach (@$entries) {
+ my $flags = $_->{'flags'};
+ my @insertCount = (($flags & 0x03e0) >> 5, ($flags & 0x001f));
+ my $actions = $_->{'actions'};
+ foreach (0 .. 1) {
+ if ($insertCount[$_] > 0) {
+ $fh->seek($stateTableStart + $actions->[$_], IO::File::SEEK_SET);
+ $fh->read($dat, $insertCount[$_] * 2);
+ if (not defined $insertListHash{$dat}) {
+ push @$insertLists, [unpack("n*", $dat)];
+ $insertListHash{$dat} = $#$insertLists;
+ }
+ $actions->[$_] = $insertListHash{$dat};
+ }
+ else {
+ $actions->[$_] = undef;
+ }
+ }
+ }
+
+ $subtable->{'classes'} = $classes;
+ $subtable->{'states'} = $states;
+ $subtable->{'insertLists'} = $insertLists;
+ }
+
+ else {
+ die "unknown subtable type";
+ }
+
+ push @$subtables, $subtable;
+ $fh->seek($subtableStart + $length, IO::File::SEEK_SET);
+ }
+
+ push @$chains, {
+ 'defaultFlags' => $defaultFlags,
+ 'featureEntries' => $featureEntries,
+ 'subtables' => $subtables
+ };
+ $fh->seek($chainStart + $chainLength, IO::File::SEEK_SET);
+ }
+
+ $self->{'chains'} = $chains;
+
+ $self;
+}
+
+=head2 $t->out($fh)
+
+Writes the table to a file either from memory or by copying
+
+=cut
+
+sub out
+{
+ my ($self, $fh) = @_;
+
+ return $self->SUPER::out($fh) unless $self->{' read'};
+
+ my $chains = $self->{'chains'};
+ $fh->print(TTF_Pack("fL", $self->{'version'}, scalar @$chains));
+
+ foreach (@$chains) {
+ my $chainStart = $fh->tell();
+ my ($featureEntries, $subtables) = ($_->{'featureEntries'}, $_->{'subtables'});
+ $fh->print(TTF_Pack("LLSS", $_->{'defaultFlags'}, 0, scalar @$featureEntries, scalar @$subtables)); # placeholder for length
+
+ foreach (@$featureEntries) {
+ $fh->print(TTF_Pack("SSLL", $_->{'type'}, $_->{'setting'}, $_->{'enable'}, $_->{'disable'}));
+ }
+
+ foreach (@$subtables) {
+ my $subtableStart = $fh->tell();
+ my $type = $_->{'type'};
+ my $coverage = $type;
+ $coverage += 0x4000 if $_->{'direction'} eq 'RL';
+ $coverage += 0x2000 if $_->{'orientation'} eq 'VH';
+ $coverage += 0x8000 if $_->{'orientation'} eq 'V';
+
+ $fh->print(TTF_Pack("SSL", 0, $coverage, $_->{'subFeatureFlags'})); # placeholder for length
+
+ if ($type == 0) { # rearrangement
+ AAT_write_state_table($fh, $_->{'classes'}, $_->{'states'}, 0);
+ }
+
+ elsif ($type == 1) { # contextual
+ my $stHeader = $fh->tell();
+ $fh->print(pack("nnnnn", (0) x 5)); # placeholders for stateSize, classTable, stateArray, entryTable, mappingTables
+
+ my $classTable = $fh->tell() - $stHeader;
+ my $classes = $_->{'classes'};
+ AAT_write_classes($fh, $classes);
+
+ my $stateArray = $fh->tell() - $stHeader;
+ my $states = $_->{'states'};
+ my ($stateSize, $entries) = AAT_write_states($fh, $classes, $stateArray, $states,
+ sub {
+ my $actions = $_->{'actions'};
+ ( $_->{'flags'}, @$actions )
+ }
+ );
+
+ my $entryTable = $fh->tell() - $stHeader;
+ my $offset = ($entryTable + 8 * @$entries) / 2;
+ foreach (@$entries) {
+ my ($nextState, $flags, @parts) = split /,/;
+ $fh->print(pack("nnnn", $nextState, $flags, map { $_ eq "" ? 0 : $_ + $offset } @parts));
+ }
+
+ my $mappingTables = $fh->tell() - $stHeader;
+ my $mappings = $_->{'mappings'};
+ $fh->print(pack("n*", @$mappings));
+
+ my $loc = $fh->tell();
+ $fh->seek($stHeader, IO::File::SEEK_SET);
+ $fh->print(pack("nnnnn", $stateSize, $classTable, $stateArray, $entryTable, $mappingTables));
+ $fh->seek($loc, IO::File::SEEK_SET);
+ }
+
+ elsif ($type == 2) { # ligature
+ my $stHeader = $fh->tell();
+ $fh->print(pack("nnnnnnn", (0) x 7)); # placeholders for stateSize, classTable, stateArray, entryTable, actionLists, components, ligatures
+
+ my $classTable = $fh->tell() - $stHeader;
+ my $classes = $_->{'classes'};
+ AAT_write_classes($fh, $classes);
+
+ my $stateArray = $fh->tell() - $stHeader;
+ my $states = $_->{'states'};
+
+ my ($stateSize, $entries) = AAT_write_states($fh, $classes, $stateArray, $states,
+ sub {
+ ( $_->{'flags'} & 0xc000, $_->{'actions'} )
+ }
+ );
+
+ my $actionLists = $_->{'actionLists'};
+ my %actionListOffset;
+ my $actionListDataLength = 0;
+ my @actionListEntries;
+ foreach (0 .. $#$entries) {
+ my ($nextState, $flags, $offset) = split(/,/, $entries->[$_]);
+ if ($offset eq "") {
+ $offset = undef;
+ }
+ else {
+ if (defined $actionListOffset{$offset}) {
+ $offset = $actionListOffset{$offset};
+ }
+ else {
+ $actionListOffset{$offset} = $actionListDataLength;
+ my $list = $actionLists->[$offset];
+ $actionListDataLength += 4 * @$list;
+ push @actionListEntries, $list;
+ $offset = $actionListOffset{$offset};
+ }
+ }
+ $entries->[$_] = [ $nextState, $flags, $offset ];
+ }
+ my $entryTable = $fh->tell() - $stHeader;
+ my $ligActionLists = ($entryTable + @$entries * 4 + 3) & ~3;
+ foreach (@$entries) {
+ $_->[2] += $ligActionLists if defined $_->[2];
+ $fh->print(pack("nn", $_->[0], $_->[1] + $_->[2]));
+ }
+ $fh->print(pack("C*", (0) x ($ligActionLists - $entryTable - @$entries * 4)));
+
+ die "internal error" if $fh->tell() != $ligActionLists + $stHeader;
+
+ my $componentTable = $fh->tell() - $stHeader + $actionListDataLength;
+ my $actionList;
+ foreach $actionList (@actionListEntries) {
+ foreach (0 .. $#$actionList) {
+ my $action = $actionList->[$_];
+ my $val = $action->{'component'} + $componentTable / 2;
+ $val += 0x40000000 if $val < 0;
+ $val &= 0x3fffffff;
+ $val |= 0x40000000 if $action->{'store'};
+ $val |= 0x80000000 if $_ == $#$actionList;
+ $fh->print(pack("N", $val));
+ }
+ }
+
+ die "internal error" if $fh->tell() != $componentTable + $stHeader;
+
+ my $components = $_->{'components'};
+ my $ligatureTable = $componentTable + @$components * 2;
+ $fh->print(pack("n*", map { (index($_, '+') >= 0 ? $ligatureTable : 0) + $_ } @$components));
+
+ my $ligatures = $_->{'ligatures'};
+ $fh->print(pack("n*", @$ligatures));
+
+ my $loc = $fh->tell();
+ $fh->seek($stHeader, IO::File::SEEK_SET);
+ $fh->print(pack("nnnnnnn", $stateSize, $classTable, $stateArray, $entryTable, $ligActionLists, $componentTable, $ligatureTable));
+ $fh->seek($loc, IO::File::SEEK_SET);
+ }
+
+ elsif ($type == 4) { # non-contextual
+ AAT_write_lookup($fh, $_->{'format'}, $_->{'lookup'}, 2, undef);
+ }
+
+ elsif ($type == 5) { # insertion
+ }
+
+ else {
+ die "unknown subtable type";
+ }
+
+ my $length = $fh->tell() - $subtableStart;
+ my $padBytes = (4 - ($length & 3)) & 3;
+ $fh->print(pack("C*", (0) x $padBytes));
+ $length += $padBytes;
+ $fh->seek($subtableStart, IO::File::SEEK_SET);
+ $fh->print(pack("n", $length));
+ $fh->seek($subtableStart + $length, IO::File::SEEK_SET);
+ }
+
+ my $chainLength = $fh->tell() - $chainStart;
+ $fh->seek($chainStart + 4, IO::File::SEEK_SET);
+ $fh->print(pack("N", $chainLength));
+ $fh->seek($chainStart + $chainLength, IO::File::SEEK_SET);
+ }
+}
+
+=head2 $t->print($fh)
+
+Prints a human-readable representation of the table
+
+=cut
+
+sub print
+{
+ my ($self, $fh) = @_;
+
+ $self->read;
+ my $feat = $self->{' PARENT'}->{'feat'};
+ $feat->read;
+ my $post = $self->{' PARENT'}->{'post'};
+ $post->read;
+
+ $fh = 'STDOUT' unless defined $fh;
+
+ $fh->printf("version %f\n", $self->{'version'});
+
+ my $chains = $self->{'chains'};
+ foreach (@$chains) {
+ my $defaultFlags = $_->{'defaultFlags'};
+ $fh->printf("chain: defaultFlags = %08x\n", $defaultFlags);
+
+ my $featureEntries = $_->{'featureEntries'};
+ foreach (@$featureEntries) {
+ $fh->printf("\tfeature %d, setting %d : enableFlags = %08x, disableFlags = %08x # '%s: %s'\n",
+ $_->{'type'}, $_->{'setting'}, $_->{'enable'}, $_->{'disable'},
+ $feat->settingName($_->{'type'}, $_->{'setting'}));
+ }
+
+ my $subtables = $_->{'subtables'};
+ foreach (@$subtables) {
+ my $type = $_->{'type'};
+ my $subFeatureFlags = $_->{'subFeatureFlags'};
+ $fh->printf("\n\t%s table, %s, %s, subFeatureFlags = %08x # %s (%s)\n",
+ subtable_type_($type), $_->{'direction'}, $_->{'orientation'}, $subFeatureFlags,
+ "Default " . ((($subFeatureFlags & $defaultFlags) != 0) ? "On" : "Off"),
+ join(", ",
+ map {
+ join(": ", $feat->settingName($_->{'type'}, $_->{'setting'}) )
+ } grep { ($_->{'enable'} & $subFeatureFlags) != 0 } @$featureEntries
+ ) );
+
+ if ($type == 0) { # rearrangement
+ print_classes_($fh, $_, $post);
+
+ $fh->print("\n");
+ my $states = $_->{'states'};
+ my @verbs = ( "0", "Ax->xA", "xD->Dx", "AxD->DxA",
+ "ABx->xAB", "ABx->xBA", "xCD->CDx", "xCD->DCx",
+ "AxCD->CDxA", "AxCD->DCxA", "ABxD->DxAB", "ABxD->DxBA",
+ "ABxCD->CDxAB", "ABxCD->CDxBA", "ABxCD->DCxAB", "ABxCD->DCxBA");
+ foreach (0 .. $#$states) {
+ $fh->printf("\t\tState %d:", $_);
+ my $state = $states->[$_];
+ foreach (@$state) {
+ my $flags;
+ $flags .= "!" if ($_->{'flags'} & 0x4000);
+ $flags .= "<" if ($_->{'flags'} & 0x8000);
+ $flags .= ">" if ($_->{'flags'} & 0x2000);
+ $fh->printf("\t(%s%d,%s)", $flags, $_->{'nextState'}, $verbs[($_->{'flags'} & 0x000f)]);
+ }
+ $fh->print("\n");
+ }
+ }
+
+ elsif ($type == 1) { # contextual
+ print_classes_($fh, $_, $post);
+
+ $fh->print("\n");
+ my $states = $_->{'states'};
+ foreach (0 .. $#$states) {
+ $fh->printf("\t\tState %d:", $_);
+ my $state = $states->[$_];
+ foreach (@$state) {
+ my $flags;
+ $flags .= "!" if ($_->{'flags'} & 0x4000);
+ $flags .= "*" if ($_->{'flags'} & 0x8000);
+ my $actions = $_->{'actions'};
+ $fh->printf("\t(%s%d,%s,%s)", $flags, $_->{'nextState'}, map { defined $_ ? $_ : "=" } @$actions);
+ }
+ $fh->print("\n");
+ }
+
+ $fh->print("\n");
+ my $mappings = $_->{'mappings'};
+ foreach (0 .. $#$mappings) {
+ $fh->printf("\t\tMapping %d: %d [%s]\n", $_, $mappings->[$_], $post->{'VAL'}[$mappings->[$_]]);
+ }
+ }
+
+ elsif ($type == 2) { # ligature
+ print_classes_($fh, $_, $post);
+
+ $fh->print("\n");
+ my $states = $_->{'states'};
+ foreach (0 .. $#$states) {
+ $fh->printf("\t\tState %d:", $_);
+ my $state = $states->[$_];
+ foreach (@$state) {
+ my $flags;
+ $flags .= "!" if ($_->{'flags'} & 0x4000);
+ $flags .= "*" if ($_->{'flags'} & 0x8000);
+ $fh->printf("\t(%s%d,%s)", $flags, $_->{'nextState'}, defined $_->{'actions'} ? $_->{'actions'} : "=");
+ }
+ $fh->print("\n");
+ }
+
+ $fh->print("\n");
+ my $actionLists = $_->{'actionLists'};
+ foreach (0 .. $#$actionLists) {
+ $fh->printf("\t\tList %d:\t", $_);
+ my $actionList = $actionLists->[$_];
+ $fh->printf("%s\n", join(", ", map { ($_->{'component'} . ($_->{'store'} ? "*" : "") ) } @$actionList));
+ }
+
+ my $ligatureTable = $_->{'ligatureTable'};
+
+ $fh->print("\n");
+ my $components = $_->{'components'};
+ foreach (0 .. $#$components) {
+ $fh->printf("\t\tComponent %d: %s\n", $_, $components->[$_]);
+ }
+
+ $fh->print("\n");
+ my $ligatures = $_->{'ligatures'};
+ foreach (0 .. $#$ligatures) {
+ $fh->printf("\t\tLigature %d: %d [%s]\n", $_, $ligatures->[$_], $post->{'VAL'}[$ligatures->[$_]]);
+ }
+ }
+
+ elsif ($type == 4) { # non-contextual
+ my $lookup = $_->{'lookup'};
+ $fh->printf("\t\tLookup format %d\n", $_->{'format'});
+ if (defined $lookup) {
+ foreach (sort { $a <=> $b } keys %$lookup) {
+ $fh->printf("\t\t\t%d [%s] -> %d [%s])\n", $_, $post->{'VAL'}[$_], $lookup->{$_}, $post->{'VAL'}[$lookup->{$_}]);
+ }
+ }
+ }
+
+ elsif ($type == 5) { # insertion
+ print_classes_($fh, $_, $post);
+
+ $fh->print("\n");
+ my $states = $_->{'states'};
+ foreach (0 .. $#$states) {
+ $fh->printf("\t\tState %d:", $_);
+ my $state = $states->[$_];
+ foreach (@$state) {
+ my $flags;
+ $flags .= "!" if ($_->{'flags'} & 0x4000);
+ $flags .= "*" if ($_->{'flags'} & 0x8000);
+ my $actions = $_->{'actions'};
+ $fh->printf("\t(%s%d,%s,%s)", $flags, $_->{'nextState'}, map { defined $_ ? $_ : "=" } @$actions);
+ }
+ $fh->print("\n");
+ }
+
+ $fh->print("\n");
+ my $insertLists = $_->{'insertLists'};
+ foreach (0 .. $#$insertLists) {
+ my $insertList = $insertLists->[$_];
+ $fh->printf("\t\tList %d: %s\n", $_, join(", ", map { $_ . " [" . $post->{'VAL'}[$_] . "]" } @$insertList));
+ }
+ }
+
+ else {
+ # unknown
+ }
+ }
+ }
+}
+
+sub print_classes_
+{
+ my ($fh, $subtable, $post) = @_;
+
+ my $classes = $subtable->{'classes'};
+ foreach (0 .. $#$classes) {
+ my $class = $classes->[$_];
+ if (defined $class) {
+ $fh->printf("\t\tClass %d:\t%s\n", $_, join(", ", map { $_ . " [" . $post->{'VAL'}[$_] . "]" } @$class));
+ }
+ }
+}
+
+sub subtable_type_
+{
+ my ($val) = @_;
+ my ($res);
+
+ my @types = (
+ 'Rearrangement',
+ 'Contextual',
+ 'Ligature',
+ undef,
+ 'Non-contextual',
+ 'Insertion',
+ );
+ $res = $types[$val] or ('Undefined (' . $val . ')');
+
+ $res;
+}
+
+1;
+
+=head1 BUGS
+
+None known
+
+=head1 AUTHOR
+
+Jonathan Kew L<Jonathan_Kew at sil.org>. See L<Font::TTF::Font> for copyright and
+licensing.
+
+=cut
+
Modified: packages/libfont-ttf-perl/trunk/lib/Font/TTF/PCLT.pm
===================================================================
--- packages/libfont-ttf-perl/trunk/lib/Font/TTF/PCLT.pm 2006-01-17 02:56:43 UTC (rev 1966)
+++ packages/libfont-ttf-perl/trunk/lib/Font/TTF/PCLT.pm 2006-01-17 03:07:20 UTC (rev 1967)
@@ -1,121 +1,121 @@
-package Font::TTF::PCLT;
-
-=head1 NAME
-
-Font::TTF::PCLT - PCLT TrueType font table
-
-=head1 DESCRIPTION
-
-The PCLT table holds various pieces HP-PCL specific information. Information
-here is generally not used by other software, except for the xHeight and
-CapHeight which are stored here (if the table exists in a font).
-
-=head1 INSTANCE VARIABLES
-
-Only from table and the standard:
-
- version
- FontNumber
- Pitch
- xHeight
- Style
- TypeFamily
- CapHeight
- SymbolSet
- Typeface
- CharacterComplement
- FileName
- StrokeWeight
- WidthType
- SerifStyle
-
-Notice that C<Typeface>, C<CharacterComplement> and C<FileName> return arrays
-of unsigned characters of the appropriate length
-
-=head1 METHODS
-
-=cut
-
-use strict;
-use vars qw(@ISA %fields @field_info);
-
-require Font::TTF::Table;
-use Font::TTF::Utils;
-
- at ISA = qw(Font::TTF::Table);
- at field_info = (
- 'version' => 'f',
- 'FontNumber' => 'L',
- 'Pitch' => 'S',
- 'xHeight' => 'S',
- 'Style' => 'S',
- 'TypeFamily' => 'S',
- 'CapHeight' => 'S',
- 'SymbolSet' => 'S',
- 'Typeface' => 'C16',
- 'CharacterComplement' => 'C8',
- 'FileName' => 'C6',
- 'StrokeWeight' => 'C',
- 'WidthType' => 'C',
- 'SerifStyle' => 'c');
-
-sub init
-{
- my ($k, $v, $c, $i);
- for ($i = 0; $i < $#field_info; $i += 2)
- {
- ($k, $v, $c) = TTF_Init_Fields($field_info[$i], $c, $field_info[$i + 1]);
- next unless defined $k && $k ne "";
- $fields{$k} = $v;
- }
-}
-
-
-=head2 $t->read
-
-Reads the table into memory thanks to some utility functions
-
-=cut
-
-sub read
-{
- my ($self) = @_;
- my ($dat);
-
- $self->SUPER::read || return $self;
-
- init unless defined $fields{'xHeight'};
- $self->{' INFILE'}->read($dat, 54);
-
- TTF_Read_Fields($self, $dat, \%fields);
- $self;
-}
-
-
-=head2 $t->out($fh)
-
-Writes the table to a file either from memory or by copying.
-
-=cut
-
-sub out
-{
- my ($self, $fh) = @_;
-
- return $self->SUPER::out($fh) unless $self->{' read'};
- $fh->print(TTF_Out_Fields($self, \%fields, 54));
-}
-
-1;
-
-=head1 BUGS
-
-None known
-
-=head1 AUTHOR
-
-Martin Hosken Martin_Hosken at sil.org. See L<Font::TTF::Font> for copyright and
-licensing.
-
-=cut
-
+package Font::TTF::PCLT;
+
+=head1 NAME
+
+Font::TTF::PCLT - PCLT TrueType font table
+
+=head1 DESCRIPTION
+
+The PCLT table holds various pieces HP-PCL specific information. Information
+here is generally not used by other software, except for the xHeight and
+CapHeight which are stored here (if the table exists in a font).
+
+=head1 INSTANCE VARIABLES
+
+Only from table and the standard:
+
+ version
+ FontNumber
+ Pitch
+ xHeight
+ Style
+ TypeFamily
+ CapHeight
+ SymbolSet
+ Typeface
+ CharacterComplement
+ FileName
+ StrokeWeight
+ WidthType
+ SerifStyle
+
+Notice that C<Typeface>, C<CharacterComplement> and C<FileName> return arrays
+of unsigned characters of the appropriate length
+
+=head1 METHODS
+
+=cut
+
+use strict;
+use vars qw(@ISA %fields @field_info);
+
+require Font::TTF::Table;
+use Font::TTF::Utils;
+
+ at ISA = qw(Font::TTF::Table);
+ at field_info = (
+ 'version' => 'f',
+ 'FontNumber' => 'L',
+ 'Pitch' => 'S',
+ 'xHeight' => 'S',
+ 'Style' => 'S',
+ 'TypeFamily' => 'S',
+ 'CapHeight' => 'S',
+ 'SymbolSet' => 'S',
+ 'Typeface' => 'C16',
+ 'CharacterComplement' => 'C8',
+ 'FileName' => 'C6',
+ 'StrokeWeight' => 'C',
+ 'WidthType' => 'C',
+ 'SerifStyle' => 'c');
+
+sub init
+{
+ my ($k, $v, $c, $i);
+ for ($i = 0; $i < $#field_info; $i += 2)
+ {
+ ($k, $v, $c) = TTF_Init_Fields($field_info[$i], $c, $field_info[$i + 1]);
+ next unless defined $k && $k ne "";
+ $fields{$k} = $v;
+ }
+}
+
+
+=head2 $t->read
+
+Reads the table into memory thanks to some utility functions
+
+=cut
+
+sub read
+{
+ my ($self) = @_;
+ my ($dat);
+
+ $self->SUPER::read || return $self;
+
+ init unless defined $fields{'xHeight'};
+ $self->{' INFILE'}->read($dat, 54);
+
+ TTF_Read_Fields($self, $dat, \%fields);
+ $self;
+}
+
+
+=head2 $t->out($fh)
+
+Writes the table to a file either from memory or by copying.
+
+=cut
+
+sub out
+{
+ my ($self, $fh) = @_;
+
+ return $self->SUPER::out($fh) unless $self->{' read'};
+ $fh->print(TTF_Out_Fields($self, \%fields, 54));
+}
+
+1;
+
+=head1 BUGS
+
+None known
+
+=head1 AUTHOR
+
+Martin Hosken Martin_Hosken at sil.org. See L<Font::TTF::Font> for copyright and
+licensing.
+
+=cut
+
Modified: packages/libfont-ttf-perl/trunk/lib/Font/TTF/PSNames.pm
===================================================================
--- packages/libfont-ttf-perl/trunk/lib/Font/TTF/PSNames.pm 2006-01-17 02:56:43 UTC (rev 1966)
+++ packages/libfont-ttf-perl/trunk/lib/Font/TTF/PSNames.pm 2006-01-17 03:07:20 UTC (rev 1967)
@@ -1,4439 +1,4445 @@
-package Font::TTF::PSNames;
-
-=head1 NAME
-
-Font::TTF::PSNames - Utilities for Postscript glyph name processing
-
-=head1 METHODS
-
-=cut
-
-use strict;
-use vars qw(%names %agl @EXPORT_OK);
-use Exporter qw( import );
- at EXPORT_OK = qw( parse lookup);
-
-# Adobe Glyph List for New Fonts
-# from http://partners.adobe.com/asn/tech/type/aglfn13.txt
-
-%names = (
- '0020' => 'space',
- '0021' => 'exclam',
- '0022' => 'quotedbl',
- '0023' => 'numbersign',
- '0024' => 'dollar',
- '0025' => 'percent',
- '0026' => 'ampersand',
- '0027' => 'quotesingle',
- '0028' => 'parenleft',
- '0029' => 'parenright',
- '002A' => 'asterisk',
- '002B' => 'plus',
- '002C' => 'comma',
- '002D' => 'hyphen',
- '002E' => 'period',
- '002F' => 'slash',
- '0030' => 'zero',
- '0031' => 'one',
- '0032' => 'two',
- '0033' => 'three',
- '0034' => 'four',
- '0035' => 'five',
- '0036' => 'six',
- '0037' => 'seven',
- '0038' => 'eight',
- '0039' => 'nine',
- '003A' => 'colon',
- '003B' => 'semicolon',
- '003C' => 'less',
- '003D' => 'equal',
- '003E' => 'greater',
- '003F' => 'question',
- '0040' => 'at',
- '0041' => 'A',
- '0042' => 'B',
- '0043' => 'C',
- '0044' => 'D',
- '0045' => 'E',
- '0046' => 'F',
- '0047' => 'G',
- '0048' => 'H',
- '0049' => 'I',
- '004A' => 'J',
- '004B' => 'K',
- '004C' => 'L',
- '004D' => 'M',
- '004E' => 'N',
- '004F' => 'O',
- '0050' => 'P',
- '0051' => 'Q',
- '0052' => 'R',
- '0053' => 'S',
- '0054' => 'T',
- '0055' => 'U',
- '0056' => 'V',
- '0057' => 'W',
- '0058' => 'X',
- '0059' => 'Y',
- '005A' => 'Z',
- '005B' => 'bracketleft',
- '005C' => 'backslash',
- '005D' => 'bracketright',
- '005E' => 'asciicircum',
- '005F' => 'underscore',
- '0060' => 'grave',
- '0061' => 'a',
- '0062' => 'b',
- '0063' => 'c',
- '0064' => 'd',
- '0065' => 'e',
- '0066' => 'f',
- '0067' => 'g',
- '0068' => 'h',
- '0069' => 'i',
- '006A' => 'j',
- '006B' => 'k',
- '006C' => 'l',
- '006D' => 'm',
- '006E' => 'n',
- '006F' => 'o',
- '0070' => 'p',
- '0071' => 'q',
- '0072' => 'r',
- '0073' => 's',
- '0074' => 't',
- '0075' => 'u',
- '0076' => 'v',
- '0077' => 'w',
- '0078' => 'x',
- '0079' => 'y',
- '007A' => 'z',
- '007B' => 'braceleft',
- '007C' => 'bar',
- '007D' => 'braceright',
- '007E' => 'asciitilde',
-# '00A0' => 'space',
- '00A1' => 'exclamdown',
- '00A2' => 'cent',
- '00A3' => 'sterling',
- '00A4' => 'currency',
- '00A5' => 'yen',
- '00A6' => 'brokenbar',
- '00A7' => 'section',
- '00A8' => 'dieresis',
- '00A9' => 'copyright',
- '00AA' => 'ordfeminine',
- '00AB' => 'guillemotleft',
- '00AC' => 'logicalnot',
-# '00AD' => 'hyphen',
- '00AE' => 'registered',
- '00AF' => 'macron',
- '00B0' => 'degree',
- '00B1' => 'plusminus',
- '00B2' => 'twosuperior',
- '00B3' => 'threesuperior',
- '00B4' => 'acute',
- '00B5' => 'mu',
- '00B6' => 'paragraph',
- '00B7' => 'periodcentered',
- '00B8' => 'cedilla',
- '00B9' => 'onesuperior',
- '00BA' => 'ordmasculine',
- '00BB' => 'guillemotright',
- '00BC' => 'onequarter',
- '00BD' => 'onehalf',
- '00BE' => 'threequarters',
- '00BF' => 'questiondown',
- '00C0' => 'Agrave',
- '00C1' => 'Aacute',
- '00C2' => 'Acircumflex',
- '00C3' => 'Atilde',
- '00C4' => 'Adieresis',
- '00C5' => 'Aring',
- '00C6' => 'AE',
- '00C7' => 'Ccedilla',
- '00C8' => 'Egrave',
- '00C9' => 'Eacute',
- '00CA' => 'Ecircumflex',
- '00CB' => 'Edieresis',
- '00CC' => 'Igrave',
- '00CD' => 'Iacute',
- '00CE' => 'Icircumflex',
- '00CF' => 'Idieresis',
- '00D0' => 'Eth',
- '00D1' => 'Ntilde',
- '00D2' => 'Ograve',
- '00D3' => 'Oacute',
- '00D4' => 'Ocircumflex',
- '00D5' => 'Otilde',
- '00D6' => 'Odieresis',
- '00D7' => 'multiply',
- '00D8' => 'Oslash',
- '00D9' => 'Ugrave',
- '00DA' => 'Uacute',
- '00DB' => 'Ucircumflex',
- '00DC' => 'Udieresis',
- '00DD' => 'Yacute',
- '00DE' => 'Thorn',
- '00DF' => 'germandbls',
- '00E0' => 'agrave',
- '00E1' => 'aacute',
- '00E2' => 'acircumflex',
- '00E3' => 'atilde',
- '00E4' => 'adieresis',
- '00E5' => 'aring',
- '00E6' => 'ae',
- '00E7' => 'ccedilla',
- '00E8' => 'egrave',
- '00E9' => 'eacute',
- '00EA' => 'ecircumflex',
- '00EB' => 'edieresis',
- '00EC' => 'igrave',
- '00ED' => 'iacute',
- '00EE' => 'icircumflex',
- '00EF' => 'idieresis',
- '00F0' => 'eth',
- '00F1' => 'ntilde',
- '00F2' => 'ograve',
- '00F3' => 'oacute',
- '00F4' => 'ocircumflex',
- '00F5' => 'otilde',
- '00F6' => 'odieresis',
- '00F7' => 'divide',
- '00F8' => 'oslash',
- '00F9' => 'ugrave',
- '00FA' => 'uacute',
- '00FB' => 'ucircumflex',
- '00FC' => 'udieresis',
- '00FD' => 'yacute',
- '00FE' => 'thorn',
- '00FF' => 'ydieresis',
- '0100' => 'Amacron',
- '0101' => 'amacron',
- '0102' => 'Abreve',
- '0103' => 'abreve',
- '0104' => 'Aogonek',
- '0105' => 'aogonek',
- '0106' => 'Cacute',
- '0107' => 'cacute',
- '0108' => 'Ccircumflex',
- '0109' => 'ccircumflex',
- '010A' => 'Cdotaccent',
- '010B' => 'cdotaccent',
- '010C' => 'Ccaron',
- '010D' => 'ccaron',
- '010E' => 'Dcaron',
- '010F' => 'dcaron',
- '0110' => 'Dcroat',
- '0111' => 'dcroat',
- '0112' => 'Emacron',
- '0113' => 'emacron',
- '0114' => 'Ebreve',
- '0115' => 'ebreve',
- '0116' => 'Edotaccent',
- '0117' => 'edotaccent',
- '0118' => 'Eogonek',
- '0119' => 'eogonek',
- '011A' => 'Ecaron',
- '011B' => 'ecaron',
- '011C' => 'Gcircumflex',
- '011D' => 'gcircumflex',
- '011E' => 'Gbreve',
- '011F' => 'gbreve',
- '0120' => 'Gdotaccent',
- '0121' => 'gdotaccent',
- '0122' => 'Gcommaaccent',
- '0123' => 'gcommaaccent',
- '0124' => 'Hcircumflex',
- '0125' => 'hcircumflex',
- '0126' => 'Hbar',
- '0127' => 'hbar',
- '0128' => 'Itilde',
- '0129' => 'itilde',
- '012A' => 'Imacron',
- '012B' => 'imacron',
- '012C' => 'Ibreve',
- '012D' => 'ibreve',
- '012E' => 'Iogonek',
- '012F' => 'iogonek',
- '0130' => 'Idotaccent',
- '0131' => 'dotlessi',
- '0132' => 'IJ',
- '0133' => 'ij',
- '0134' => 'Jcircumflex',
- '0135' => 'jcircumflex',
- '0136' => 'Kcommaaccent',
- '0137' => 'kcommaaccent',
- '0138' => 'kgreenlandic',
- '0139' => 'Lacute',
- '013A' => 'lacute',
- '013B' => 'Lcommaaccent',
- '013C' => 'lcommaaccent',
- '013D' => 'Lcaron',
- '013E' => 'lcaron',
- '013F' => 'Ldot',
- '0140' => 'ldot',
- '0141' => 'Lslash',
- '0142' => 'lslash',
- '0143' => 'Nacute',
- '0144' => 'nacute',
- '0145' => 'Ncommaaccent',
- '0146' => 'ncommaaccent',
- '0147' => 'Ncaron',
- '0148' => 'ncaron',
- '0149' => 'napostrophe',
- '014A' => 'Eng',
- '014B' => 'eng',
- '014C' => 'Omacron',
- '014D' => 'omacron',
- '014E' => 'Obreve',
- '014F' => 'obreve',
- '0150' => 'Ohungarumlaut',
- '0151' => 'ohungarumlaut',
- '0152' => 'OE',
- '0153' => 'oe',
- '0154' => 'Racute',
- '0155' => 'racute',
- '0156' => 'Rcommaaccent',
- '0157' => 'rcommaaccent',
- '0158' => 'Rcaron',
- '0159' => 'rcaron',
- '015A' => 'Sacute',
- '015B' => 'sacute',
- '015C' => 'Scircumflex',
- '015D' => 'scircumflex',
- '015E' => 'Scedilla',
- '015F' => 'scedilla',
- '0160' => 'Scaron',
- '0161' => 'scaron',
- '0162' => 'Tcommaaccent',
- '0163' => 'tcommaaccent',
- '0164' => 'Tcaron',
- '0165' => 'tcaron',
- '0166' => 'Tbar',
- '0167' => 'tbar',
- '0168' => 'Utilde',
- '0169' => 'utilde',
- '016A' => 'Umacron',
- '016B' => 'umacron',
- '016C' => 'Ubreve',
- '016D' => 'ubreve',
- '016E' => 'Uring',
- '016F' => 'uring',
- '0170' => 'Uhungarumlaut',
- '0171' => 'uhungarumlaut',
- '0172' => 'Uogonek',
- '0173' => 'uogonek',
- '0174' => 'Wcircumflex',
- '0175' => 'wcircumflex',
- '0176' => 'Ycircumflex',
- '0177' => 'ycircumflex',
- '0178' => 'Ydieresis',
- '0179' => 'Zacute',
- '017A' => 'zacute',
- '017B' => 'Zdotaccent',
- '017C' => 'zdotaccent',
- '017D' => 'Zcaron',
- '017E' => 'zcaron',
- '017F' => 'longs',
- '0192' => 'florin',
- '01A0' => 'Ohorn',
- '01A1' => 'ohorn',
- '01AF' => 'Uhorn',
- '01B0' => 'uhorn',
- '01E6' => 'Gcaron',
- '01E7' => 'gcaron',
- '01FA' => 'Aringacute',
- '01FB' => 'aringacute',
- '01FC' => 'AEacute',
- '01FD' => 'aeacute',
- '01FE' => 'Oslashacute',
- '01FF' => 'oslashacute',
- '0218' => 'Scommaaccent',
- '0219' => 'scommaaccent',
-# '021A' => 'Tcommaaccent',
-# '021B' => 'tcommaaccent',
- '02BC' => 'afii57929',
- '02BD' => 'afii64937',
- '02C6' => 'circumflex',
- '02C7' => 'caron',
-# '02C9' => 'macron',
- '02D8' => 'breve',
- '02D9' => 'dotaccent',
- '02DA' => 'ring',
- '02DB' => 'ogonek',
- '02DC' => 'tilde',
- '02DD' => 'hungarumlaut',
- '0300' => 'gravecomb',
- '0301' => 'acutecomb',
- '0303' => 'tildecomb',
- '0309' => 'hookabovecomb',
- '0323' => 'dotbelowcomb',
- '0384' => 'tonos',
- '0385' => 'dieresistonos',
- '0386' => 'Alphatonos',
- '0387' => 'anoteleia',
- '0388' => 'Epsilontonos',
- '0389' => 'Etatonos',
- '038A' => 'Iotatonos',
- '038C' => 'Omicrontonos',
- '038E' => 'Upsilontonos',
- '038F' => 'Omegatonos',
- '0390' => 'iotadieresistonos',
- '0391' => 'Alpha',
- '0392' => 'Beta',
- '0393' => 'Gamma',
-# '0394' => 'Delta',
- '0395' => 'Epsilon',
- '0396' => 'Zeta',
- '0397' => 'Eta',
- '0398' => 'Theta',
- '0399' => 'Iota',
- '039A' => 'Kappa',
- '039B' => 'Lambda',
- '039C' => 'Mu',
- '039D' => 'Nu',
- '039E' => 'Xi',
- '039F' => 'Omicron',
- '03A0' => 'Pi',
- '03A1' => 'Rho',
- '03A3' => 'Sigma',
- '03A4' => 'Tau',
- '03A5' => 'Upsilon',
- '03A6' => 'Phi',
- '03A7' => 'Chi',
- '03A8' => 'Psi',
-# '03A9' => 'Omega',
- '03AA' => 'Iotadieresis',
- '03AB' => 'Upsilondieresis',
- '03AC' => 'alphatonos',
- '03AD' => 'epsilontonos',
- '03AE' => 'etatonos',
- '03AF' => 'iotatonos',
- '03B0' => 'upsilondieresistonos',
- '03B1' => 'alpha',
- '03B2' => 'beta',
- '03B3' => 'gamma',
- '03B4' => 'delta',
- '03B5' => 'epsilon',
- '03B6' => 'zeta',
- '03B7' => 'eta',
- '03B8' => 'theta',
- '03B9' => 'iota',
- '03BA' => 'kappa',
- '03BB' => 'lambda',
-# '03BC' => 'mu',
- '03BD' => 'nu',
- '03BE' => 'xi',
- '03BF' => 'omicron',
- '03C0' => 'pi',
- '03C1' => 'rho',
- '03C2' => 'sigma1',
- '03C3' => 'sigma',
- '03C4' => 'tau',
- '03C5' => 'upsilon',
- '03C6' => 'phi',
- '03C7' => 'chi',
- '03C8' => 'psi',
- '03C9' => 'omega',
- '03CA' => 'iotadieresis',
- '03CB' => 'upsilondieresis',
- '03CC' => 'omicrontonos',
- '03CD' => 'upsilontonos',
- '03CE' => 'omegatonos',
- '03D1' => 'theta1',
- '03D2' => 'Upsilon1',
- '03D5' => 'phi1',
- '03D6' => 'omega1',
- '0401' => 'afii10023',
- '0402' => 'afii10051',
- '0403' => 'afii10052',
- '0404' => 'afii10053',
- '0405' => 'afii10054',
- '0406' => 'afii10055',
- '0407' => 'afii10056',
- '0408' => 'afii10057',
- '0409' => 'afii10058',
- '040A' => 'afii10059',
- '040B' => 'afii10060',
- '040C' => 'afii10061',
- '040E' => 'afii10062',
- '040F' => 'afii10145',
- '0410' => 'afii10017',
- '0411' => 'afii10018',
- '0412' => 'afii10019',
- '0413' => 'afii10020',
- '0414' => 'afii10021',
- '0415' => 'afii10022',
- '0416' => 'afii10024',
- '0417' => 'afii10025',
- '0418' => 'afii10026',
- '0419' => 'afii10027',
- '041A' => 'afii10028',
- '041B' => 'afii10029',
- '041C' => 'afii10030',
- '041D' => 'afii10031',
- '041E' => 'afii10032',
- '041F' => 'afii10033',
- '0420' => 'afii10034',
- '0421' => 'afii10035',
- '0422' => 'afii10036',
- '0423' => 'afii10037',
- '0424' => 'afii10038',
- '0425' => 'afii10039',
- '0426' => 'afii10040',
- '0427' => 'afii10041',
- '0428' => 'afii10042',
- '0429' => 'afii10043',
- '042A' => 'afii10044',
- '042B' => 'afii10045',
- '042C' => 'afii10046',
- '042D' => 'afii10047',
- '042E' => 'afii10048',
- '042F' => 'afii10049',
- '0430' => 'afii10065',
- '0431' => 'afii10066',
- '0432' => 'afii10067',
- '0433' => 'afii10068',
- '0434' => 'afii10069',
- '0435' => 'afii10070',
- '0436' => 'afii10072',
- '0437' => 'afii10073',
- '0438' => 'afii10074',
- '0439' => 'afii10075',
- '043A' => 'afii10076',
- '043B' => 'afii10077',
- '043C' => 'afii10078',
- '043D' => 'afii10079',
- '043E' => 'afii10080',
- '043F' => 'afii10081',
- '0440' => 'afii10082',
- '0441' => 'afii10083',
- '0442' => 'afii10084',
- '0443' => 'afii10085',
- '0444' => 'afii10086',
- '0445' => 'afii10087',
- '0446' => 'afii10088',
- '0447' => 'afii10089',
- '0448' => 'afii10090',
- '0449' => 'afii10091',
- '044A' => 'afii10092',
- '044B' => 'afii10093',
- '044C' => 'afii10094',
- '044D' => 'afii10095',
- '044E' => 'afii10096',
- '044F' => 'afii10097',
- '0451' => 'afii10071',
- '0452' => 'afii10099',
- '0453' => 'afii10100',
- '0454' => 'afii10101',
- '0455' => 'afii10102',
- '0456' => 'afii10103',
- '0457' => 'afii10104',
- '0458' => 'afii10105',
- '0459' => 'afii10106',
- '045A' => 'afii10107',
- '045B' => 'afii10108',
- '045C' => 'afii10109',
- '045E' => 'afii10110',
- '045F' => 'afii10193',
- '0462' => 'afii10146',
- '0463' => 'afii10194',
- '0472' => 'afii10147',
- '0473' => 'afii10195',
- '0474' => 'afii10148',
- '0475' => 'afii10196',
- '0490' => 'afii10050',
- '0491' => 'afii10098',
- '04D9' => 'afii10846',
- '05B0' => 'afii57799',
- '05B1' => 'afii57801',
- '05B2' => 'afii57800',
- '05B3' => 'afii57802',
- '05B4' => 'afii57793',
- '05B5' => 'afii57794',
- '05B6' => 'afii57795',
- '05B7' => 'afii57798',
- '05B8' => 'afii57797',
- '05B9' => 'afii57806',
- '05BB' => 'afii57796',
- '05BC' => 'afii57807',
- '05BD' => 'afii57839',
- '05BE' => 'afii57645',
- '05BF' => 'afii57841',
- '05C0' => 'afii57842',
- '05C1' => 'afii57804',
- '05C2' => 'afii57803',
- '05C3' => 'afii57658',
- '05D0' => 'afii57664',
- '05D1' => 'afii57665',
- '05D2' => 'afii57666',
- '05D3' => 'afii57667',
- '05D4' => 'afii57668',
- '05D5' => 'afii57669',
- '05D6' => 'afii57670',
- '05D7' => 'afii57671',
- '05D8' => 'afii57672',
- '05D9' => 'afii57673',
- '05DA' => 'afii57674',
- '05DB' => 'afii57675',
- '05DC' => 'afii57676',
- '05DD' => 'afii57677',
- '05DE' => 'afii57678',
- '05DF' => 'afii57679',
- '05E0' => 'afii57680',
- '05E1' => 'afii57681',
- '05E2' => 'afii57682',
- '05E3' => 'afii57683',
- '05E4' => 'afii57684',
- '05E5' => 'afii57685',
- '05E6' => 'afii57686',
- '05E7' => 'afii57687',
- '05E8' => 'afii57688',
- '05E9' => 'afii57689',
- '05EA' => 'afii57690',
- '05F0' => 'afii57716',
- '05F1' => 'afii57717',
- '05F2' => 'afii57718',
- '060C' => 'afii57388',
- '061B' => 'afii57403',
- '061F' => 'afii57407',
- '0621' => 'afii57409',
- '0622' => 'afii57410',
- '0623' => 'afii57411',
- '0624' => 'afii57412',
- '0625' => 'afii57413',
- '0626' => 'afii57414',
- '0627' => 'afii57415',
- '0628' => 'afii57416',
- '0629' => 'afii57417',
- '062A' => 'afii57418',
- '062B' => 'afii57419',
- '062C' => 'afii57420',
- '062D' => 'afii57421',
- '062E' => 'afii57422',
- '062F' => 'afii57423',
- '0630' => 'afii57424',
- '0631' => 'afii57425',
- '0632' => 'afii57426',
- '0633' => 'afii57427',
- '0634' => 'afii57428',
- '0635' => 'afii57429',
- '0636' => 'afii57430',
- '0637' => 'afii57431',
- '0638' => 'afii57432',
- '0639' => 'afii57433',
- '063A' => 'afii57434',
- '0640' => 'afii57440',
- '0641' => 'afii57441',
- '0642' => 'afii57442',
- '0643' => 'afii57443',
- '0644' => 'afii57444',
- '0645' => 'afii57445',
- '0646' => 'afii57446',
- '0647' => 'afii57470',
- '0648' => 'afii57448',
- '0649' => 'afii57449',
- '064A' => 'afii57450',
- '064B' => 'afii57451',
- '064C' => 'afii57452',
- '064D' => 'afii57453',
- '064E' => 'afii57454',
- '064F' => 'afii57455',
- '0650' => 'afii57456',
- '0651' => 'afii57457',
- '0652' => 'afii57458',
- '0660' => 'afii57392',
- '0661' => 'afii57393',
- '0662' => 'afii57394',
- '0663' => 'afii57395',
- '0664' => 'afii57396',
- '0665' => 'afii57397',
- '0666' => 'afii57398',
- '0667' => 'afii57399',
- '0668' => 'afii57400',
- '0669' => 'afii57401',
- '066A' => 'afii57381',
- '066D' => 'afii63167',
- '0679' => 'afii57511',
- '067E' => 'afii57506',
- '0686' => 'afii57507',
- '0688' => 'afii57512',
- '0691' => 'afii57513',
- '0698' => 'afii57508',
- '06A4' => 'afii57505',
- '06AF' => 'afii57509',
- '06BA' => 'afii57514',
- '06D2' => 'afii57519',
- '06D5' => 'afii57534',
- '1E80' => 'Wgrave',
- '1E81' => 'wgrave',
- '1E82' => 'Wacute',
- '1E83' => 'wacute',
- '1E84' => 'Wdieresis',
- '1E85' => 'wdieresis',
- '1EF2' => 'Ygrave',
- '1EF3' => 'ygrave',
- '200C' => 'afii61664',
- '200D' => 'afii301',
- '200E' => 'afii299',
- '200F' => 'afii300',
- '2012' => 'figuredash',
- '2013' => 'endash',
- '2014' => 'emdash',
- '2015' => 'afii00208',
- '2017' => 'underscoredbl',
- '2018' => 'quoteleft',
- '2019' => 'quoteright',
- '201A' => 'quotesinglbase',
- '201B' => 'quotereversed',
- '201C' => 'quotedblleft',
- '201D' => 'quotedblright',
- '201E' => 'quotedblbase',
- '2020' => 'dagger',
- '2021' => 'daggerdbl',
- '2022' => 'bullet',
- '2024' => 'onedotenleader',
- '2025' => 'twodotenleader',
- '2026' => 'ellipsis',
- '202C' => 'afii61573',
- '202D' => 'afii61574',
- '202E' => 'afii61575',
- '2030' => 'perthousand',
- '2032' => 'minute',
- '2033' => 'second',
- '2039' => 'guilsinglleft',
- '203A' => 'guilsinglright',
- '203C' => 'exclamdbl',
- '2044' => 'fraction',
-# '2070' => 'zerosuperior',
-# '2074' => 'foursuperior',
-# '2075' => 'fivesuperior',
-# '2076' => 'sixsuperior',
-# '2077' => 'sevensuperior',
-# '2078' => 'eightsuperior',
-# '2079' => 'ninesuperior',
-# '207D' => 'parenleftsuperior',
-# '207E' => 'parenrightsuperior',
-# '207F' => 'nsuperior',
-# '2080' => 'zeroinferior',
-# '2081' => 'oneinferior',
-# '2082' => 'twoinferior',
-# '2083' => 'threeinferior',
-# '2084' => 'fourinferior',
-# '2085' => 'fiveinferior',
-# '2086' => 'sixinferior',
-# '2087' => 'seveninferior',
-# '2088' => 'eightinferior',
-# '2089' => 'nineinferior',
-# '208D' => 'parenleftinferior',
-# '208E' => 'parenrightinferior',
- '20A1' => 'colonmonetary',
- '20A3' => 'franc',
- '20A4' => 'lira',
- '20A7' => 'peseta',
- '20AA' => 'afii57636',
- '20AB' => 'dong',
- '20AC' => 'Euro',
- '2105' => 'afii61248',
- '2111' => 'Ifraktur',
- '2113' => 'afii61289',
- '2116' => 'afii61352',
- '2118' => 'weierstrass',
- '211C' => 'Rfraktur',
- '211E' => 'prescription',
- '2122' => 'trademark',
- '2126' => 'Omega',
- '212E' => 'estimated',
- '2135' => 'aleph',
- '2153' => 'onethird',
- '2154' => 'twothirds',
- '215B' => 'oneeighth',
- '215C' => 'threeeighths',
- '215D' => 'fiveeighths',
- '215E' => 'seveneighths',
- '2190' => 'arrowleft',
- '2191' => 'arrowup',
- '2192' => 'arrowright',
- '2193' => 'arrowdown',
- '2194' => 'arrowboth',
- '2195' => 'arrowupdn',
- '21A8' => 'arrowupdnbse',
- '21B5' => 'carriagereturn',
- '21D0' => 'arrowdblleft',
- '21D1' => 'arrowdblup',
- '21D2' => 'arrowdblright',
- '21D3' => 'arrowdbldown',
- '21D4' => 'arrowdblboth',
- '2200' => 'universal',
- '2202' => 'partialdiff',
- '2203' => 'existential',
- '2205' => 'emptyset',
- '2206' => 'Delta',
- '2207' => 'gradient',
- '2208' => 'element',
- '2209' => 'notelement',
- '220B' => 'suchthat',
- '220F' => 'product',
- '2211' => 'summation',
- '2212' => 'minus',
-# '2215' => 'fraction',
- '2217' => 'asteriskmath',
-# '2219' => 'periodcentered',
- '221A' => 'radical',
- '221D' => 'proportional',
- '221E' => 'infinity',
- '221F' => 'orthogonal',
- '2220' => 'angle',
- '2227' => 'logicaland',
- '2228' => 'logicalor',
- '2229' => 'intersection',
- '222A' => 'union',
- '222B' => 'integral',
- '2234' => 'therefore',
- '223C' => 'similar',
- '2245' => 'congruent',
- '2248' => 'approxequal',
- '2260' => 'notequal',
- '2261' => 'equivalence',
- '2264' => 'lessequal',
- '2265' => 'greaterequal',
- '2282' => 'propersubset',
- '2283' => 'propersuperset',
- '2284' => 'notsubset',
- '2286' => 'reflexsubset',
- '2287' => 'reflexsuperset',
- '2295' => 'circleplus',
- '2297' => 'circlemultiply',
- '22A5' => 'perpendicular',
- '22C5' => 'dotmath',
- '2302' => 'house',
- '2310' => 'revlogicalnot',
- '2320' => 'integraltp',
- '2321' => 'integralbt',
- '2329' => 'angleleft',
- '232A' => 'angleright',
- '2500' => 'SF100000',
- '2502' => 'SF110000',
- '250C' => 'SF010000',
- '2510' => 'SF030000',
- '2514' => 'SF020000',
- '2518' => 'SF040000',
- '251C' => 'SF080000',
- '2524' => 'SF090000',
- '252C' => 'SF060000',
- '2534' => 'SF070000',
- '253C' => 'SF050000',
- '2550' => 'SF430000',
- '2551' => 'SF240000',
- '2552' => 'SF510000',
- '2553' => 'SF520000',
- '2554' => 'SF390000',
- '2555' => 'SF220000',
- '2556' => 'SF210000',
- '2557' => 'SF250000',
- '2558' => 'SF500000',
- '2559' => 'SF490000',
- '255A' => 'SF380000',
- '255B' => 'SF280000',
- '255C' => 'SF270000',
- '255D' => 'SF260000',
- '255E' => 'SF360000',
- '255F' => 'SF370000',
- '2560' => 'SF420000',
- '2561' => 'SF190000',
- '2562' => 'SF200000',
- '2563' => 'SF230000',
- '2564' => 'SF470000',
- '2565' => 'SF480000',
- '2566' => 'SF410000',
- '2567' => 'SF450000',
- '2568' => 'SF460000',
- '2569' => 'SF400000',
- '256A' => 'SF540000',
- '256B' => 'SF530000',
- '256C' => 'SF440000',
- '2580' => 'upblock',
- '2584' => 'dnblock',
- '2588' => 'block',
- '258C' => 'lfblock',
- '2590' => 'rtblock',
- '2591' => 'ltshade',
- '2592' => 'shade',
- '2593' => 'dkshade',
- '25A0' => 'filledbox',
- '25A1' => 'H22073',
- '25AA' => 'H18543',
- '25AB' => 'H18551',
- '25AC' => 'filledrect',
- '25B2' => 'triagup',
- '25BA' => 'triagrt',
- '25BC' => 'triagdn',
- '25C4' => 'triaglf',
- '25CA' => 'lozenge',
- '25CB' => 'circle',
- '25CF' => 'H18533',
- '25D8' => 'invbullet',
- '25D9' => 'invcircle',
- '25E6' => 'openbullet',
- '263A' => 'smileface',
- '263B' => 'invsmileface',
- '263C' => 'sun',
- '2640' => 'female',
- '2642' => 'male',
- '2660' => 'spade',
- '2663' => 'club',
- '2665' => 'heart',
- '2666' => 'diamond',
- '266A' => 'musicalnote',
- '266B' => 'musicalnotedbl',
- 'FB00' => 'ff',
- 'FB01' => 'fi',
- 'FB02' => 'fl',
- 'FB03' => 'ffi',
- 'FB04' => 'ffl',
- 'FB1F' => 'afii57705',
- 'FB2A' => 'afii57694',
- 'FB2B' => 'afii57695',
- 'FB35' => 'afii57723',
- 'FB4B' => 'afii57700',
-);
-
-# Adobe Glyph List 2.0 (sans those in glyph list for *new* fonts) -- thus
-# these are all historic names that could occur in fonts
-# from http://partners.adobe.com/asn/tech/type/glyphlist.txt
-
-%agl = (
- 'AEmacron' => "\x{01E2}",
- 'AEsmall' => "\x{F7E6}",
- 'Aacutesmall' => "\x{F7E1}",
- 'Abreveacute' => "\x{1EAE}",
- 'Abrevecyrillic' => "\x{04D0}",
- 'Abrevedotbelow' => "\x{1EB6}",
- 'Abrevegrave' => "\x{1EB0}",
- 'Abrevehookabove' => "\x{1EB2}",
- 'Abrevetilde' => "\x{1EB4}",
- 'Acaron' => "\x{01CD}",
- 'Acircle' => "\x{24B6}",
- 'Acircumflexacute' => "\x{1EA4}",
- 'Acircumflexdotbelow' => "\x{1EAC}",
- 'Acircumflexgrave' => "\x{1EA6}",
- 'Acircumflexhookabove' => "\x{1EA8}",
- 'Acircumflexsmall' => "\x{F7E2}",
- 'Acircumflextilde' => "\x{1EAA}",
- 'Acute' => "\x{F6C9}",
- 'Acutesmall' => "\x{F7B4}",
- 'Acyrillic' => "\x{0410}",
- 'Adblgrave' => "\x{0200}",
- 'Adieresiscyrillic' => "\x{04D2}",
- 'Adieresismacron' => "\x{01DE}",
- 'Adieresissmall' => "\x{F7E4}",
- 'Adotbelow' => "\x{1EA0}",
- 'Adotmacron' => "\x{01E0}",
- 'Agravesmall' => "\x{F7E0}",
- 'Ahookabove' => "\x{1EA2}",
- 'Aiecyrillic' => "\x{04D4}",
- 'Ainvertedbreve' => "\x{0202}",
- 'Amonospace' => "\x{FF21}",
- 'Aringbelow' => "\x{1E00}",
- 'Aringsmall' => "\x{F7E5}",
- 'Asmall' => "\x{F761}",
- 'Atildesmall' => "\x{F7E3}",
- 'Aybarmenian' => "\x{0531}",
- 'Bcircle' => "\x{24B7}",
- 'Bdotaccent' => "\x{1E02}",
- 'Bdotbelow' => "\x{1E04}",
- 'Becyrillic' => "\x{0411}",
- 'Benarmenian' => "\x{0532}",
- 'Bhook' => "\x{0181}",
- 'Blinebelow' => "\x{1E06}",
- 'Bmonospace' => "\x{FF22}",
- 'Brevesmall' => "\x{F6F4}",
- 'Bsmall' => "\x{F762}",
- 'Btopbar' => "\x{0182}",
- 'Caarmenian' => "\x{053E}",
- 'Caron' => "\x{F6CA}",
- 'Caronsmall' => "\x{F6F5}",
- 'Ccedillaacute' => "\x{1E08}",
- 'Ccedillasmall' => "\x{F7E7}",
- 'Ccircle' => "\x{24B8}",
- 'Cdot' => "\x{010A}",
- 'Cedillasmall' => "\x{F7B8}",
- 'Chaarmenian' => "\x{0549}",
- 'Cheabkhasiancyrillic' => "\x{04BC}",
- 'Checyrillic' => "\x{0427}",
- 'Chedescenderabkhasiancyrillic' => "\x{04BE}",
- 'Chedescendercyrillic' => "\x{04B6}",
- 'Chedieresiscyrillic' => "\x{04F4}",
- 'Cheharmenian' => "\x{0543}",
- 'Chekhakassiancyrillic' => "\x{04CB}",
- 'Cheverticalstrokecyrillic' => "\x{04B8}",
- 'Chook' => "\x{0187}",
- 'Circumflexsmall' => "\x{F6F6}",
- 'Cmonospace' => "\x{FF23}",
- 'Coarmenian' => "\x{0551}",
- 'Csmall' => "\x{F763}",
- 'DZ' => "\x{01F1}",
- 'DZcaron' => "\x{01C4}",
- 'Daarmenian' => "\x{0534}",
- 'Dafrican' => "\x{0189}",
- 'Dcedilla' => "\x{1E10}",
- 'Dcircle' => "\x{24B9}",
- 'Dcircumflexbelow' => "\x{1E12}",
- 'Ddotaccent' => "\x{1E0A}",
- 'Ddotbelow' => "\x{1E0C}",
- 'Decyrillic' => "\x{0414}",
- 'Deicoptic' => "\x{03EE}",
- 'Deltagreek' => "\x{0394}",
- 'Dhook' => "\x{018A}",
- 'Dieresis' => "\x{F6CB}",
- 'DieresisAcute' => "\x{F6CC}",
- 'DieresisGrave' => "\x{F6CD}",
- 'Dieresissmall' => "\x{F7A8}",
- 'Digammagreek' => "\x{03DC}",
- 'Djecyrillic' => "\x{0402}",
- 'Dlinebelow' => "\x{1E0E}",
- 'Dmonospace' => "\x{FF24}",
- 'Dotaccentsmall' => "\x{F6F7}",
- 'Dslash' => "\x{0110}",
- 'Dsmall' => "\x{F764}",
- 'Dtopbar' => "\x{018B}",
- 'Dz' => "\x{01F2}",
- 'Dzcaron' => "\x{01C5}",
- 'Dzeabkhasiancyrillic' => "\x{04E0}",
- 'Dzecyrillic' => "\x{0405}",
- 'Dzhecyrillic' => "\x{040F}",
- 'Eacutesmall' => "\x{F7E9}",
- 'Ecedillabreve' => "\x{1E1C}",
- 'Echarmenian' => "\x{0535}",
- 'Ecircle' => "\x{24BA}",
- 'Ecircumflexacute' => "\x{1EBE}",
- 'Ecircumflexbelow' => "\x{1E18}",
- 'Ecircumflexdotbelow' => "\x{1EC6}",
- 'Ecircumflexgrave' => "\x{1EC0}",
- 'Ecircumflexhookabove' => "\x{1EC2}",
- 'Ecircumflexsmall' => "\x{F7EA}",
- 'Ecircumflextilde' => "\x{1EC4}",
- 'Ecyrillic' => "\x{0404}",
- 'Edblgrave' => "\x{0204}",
- 'Edieresissmall' => "\x{F7EB}",
- 'Edot' => "\x{0116}",
- 'Edotbelow' => "\x{1EB8}",
- 'Efcyrillic' => "\x{0424}",
- 'Egravesmall' => "\x{F7E8}",
- 'Eharmenian' => "\x{0537}",
- 'Ehookabove' => "\x{1EBA}",
- 'Eightroman' => "\x{2167}",
- 'Einvertedbreve' => "\x{0206}",
- 'Eiotifiedcyrillic' => "\x{0464}",
- 'Elcyrillic' => "\x{041B}",
- 'Elevenroman' => "\x{216A}",
- 'Emacronacute' => "\x{1E16}",
- 'Emacrongrave' => "\x{1E14}",
- 'Emcyrillic' => "\x{041C}",
- 'Emonospace' => "\x{FF25}",
- 'Encyrillic' => "\x{041D}",
- 'Endescendercyrillic' => "\x{04A2}",
- 'Enghecyrillic' => "\x{04A4}",
- 'Enhookcyrillic' => "\x{04C7}",
- 'Eopen' => "\x{0190}",
- 'Ercyrillic' => "\x{0420}",
- 'Ereversed' => "\x{018E}",
- 'Ereversedcyrillic' => "\x{042D}",
- 'Escyrillic' => "\x{0421}",
- 'Esdescendercyrillic' => "\x{04AA}",
- 'Esh' => "\x{01A9}",
- 'Esmall' => "\x{F765}",
- 'Etarmenian' => "\x{0538}",
- 'Ethsmall' => "\x{F7F0}",
- 'Etilde' => "\x{1EBC}",
- 'Etildebelow' => "\x{1E1A}",
- 'Ezh' => "\x{01B7}",
- 'Ezhcaron' => "\x{01EE}",
- 'Ezhreversed' => "\x{01B8}",
- 'Fcircle' => "\x{24BB}",
- 'Fdotaccent' => "\x{1E1E}",
- 'Feharmenian' => "\x{0556}",
- 'Feicoptic' => "\x{03E4}",
- 'Fhook' => "\x{0191}",
- 'Fitacyrillic' => "\x{0472}",
- 'Fiveroman' => "\x{2164}",
- 'Fmonospace' => "\x{FF26}",
- 'Fourroman' => "\x{2163}",
- 'Fsmall' => "\x{F766}",
- 'GBsquare' => "\x{3387}",
- 'Gacute' => "\x{01F4}",
- 'Gammaafrican' => "\x{0194}",
- 'Gangiacoptic' => "\x{03EA}",
- 'Gcedilla' => "\x{0122}",
- 'Gcircle' => "\x{24BC}",
- 'Gdot' => "\x{0120}",
- 'Gecyrillic' => "\x{0413}",
- 'Ghadarmenian' => "\x{0542}",
- 'Ghemiddlehookcyrillic' => "\x{0494}",
- 'Ghestrokecyrillic' => "\x{0492}",
- 'Gheupturncyrillic' => "\x{0490}",
- 'Ghook' => "\x{0193}",
- 'Gimarmenian' => "\x{0533}",
- 'Gjecyrillic' => "\x{0403}",
- 'Gmacron' => "\x{1E20}",
- 'Gmonospace' => "\x{FF27}",
- 'Grave' => "\x{F6CE}",
- 'Gravesmall' => "\x{F760}",
- 'Gsmall' => "\x{F767}",
- 'Gsmallhook' => "\x{029B}",
- 'Gstroke' => "\x{01E4}",
- 'HPsquare' => "\x{33CB}",
- 'Haabkhasiancyrillic' => "\x{04A8}",
- 'Hadescendercyrillic' => "\x{04B2}",
- 'Hardsigncyrillic' => "\x{042A}",
- 'Hbrevebelow' => "\x{1E2A}",
- 'Hcedilla' => "\x{1E28}",
- 'Hcircle' => "\x{24BD}",
- 'Hdieresis' => "\x{1E26}",
- 'Hdotaccent' => "\x{1E22}",
- 'Hdotbelow' => "\x{1E24}",
- 'Hmonospace' => "\x{FF28}",
- 'Hoarmenian' => "\x{0540}",
- 'Horicoptic' => "\x{03E8}",
- 'Hsmall' => "\x{F768}",
- 'Hungarumlaut' => "\x{F6CF}",
- 'Hungarumlautsmall' => "\x{F6F8}",
- 'Hzsquare' => "\x{3390}",
- 'IAcyrillic' => "\x{042F}",
- 'IUcyrillic' => "\x{042E}",
- 'Iacutesmall' => "\x{F7ED}",
- 'Icaron' => "\x{01CF}",
- 'Icircle' => "\x{24BE}",
- 'Icircumflexsmall' => "\x{F7EE}",
- 'Icyrillic' => "\x{0406}",
- 'Idblgrave' => "\x{0208}",
- 'Idieresisacute' => "\x{1E2E}",
- 'Idieresiscyrillic' => "\x{04E4}",
- 'Idieresissmall' => "\x{F7EF}",
- 'Idot' => "\x{0130}",
- 'Idotbelow' => "\x{1ECA}",
- 'Iebrevecyrillic' => "\x{04D6}",
- 'Iecyrillic' => "\x{0415}",
- 'Igravesmall' => "\x{F7EC}",
- 'Ihookabove' => "\x{1EC8}",
- 'Iicyrillic' => "\x{0418}",
- 'Iinvertedbreve' => "\x{020A}",
- 'Iishortcyrillic' => "\x{0419}",
- 'Imacroncyrillic' => "\x{04E2}",
- 'Imonospace' => "\x{FF29}",
- 'Iniarmenian' => "\x{053B}",
- 'Iocyrillic' => "\x{0401}",
- 'Iotaafrican' => "\x{0196}",
- 'Ismall' => "\x{F769}",
- 'Istroke' => "\x{0197}",
- 'Itildebelow' => "\x{1E2C}",
- 'Izhitsacyrillic' => "\x{0474}",
- 'Izhitsadblgravecyrillic' => "\x{0476}",
- 'Jaarmenian' => "\x{0541}",
- 'Jcircle' => "\x{24BF}",
- 'Jecyrillic' => "\x{0408}",
- 'Jheharmenian' => "\x{054B}",
- 'Jmonospace' => "\x{FF2A}",
- 'Jsmall' => "\x{F76A}",
- 'KBsquare' => "\x{3385}",
- 'KKsquare' => "\x{33CD}",
- 'Kabashkircyrillic' => "\x{04A0}",
- 'Kacute' => "\x{1E30}",
- 'Kacyrillic' => "\x{041A}",
- 'Kadescendercyrillic' => "\x{049A}",
- 'Kahookcyrillic' => "\x{04C3}",
- 'Kastrokecyrillic' => "\x{049E}",
- 'Kaverticalstrokecyrillic' => "\x{049C}",
- 'Kcaron' => "\x{01E8}",
- 'Kcedilla' => "\x{0136}",
- 'Kcircle' => "\x{24C0}",
- 'Kdotbelow' => "\x{1E32}",
- 'Keharmenian' => "\x{0554}",
- 'Kenarmenian' => "\x{053F}",
- 'Khacyrillic' => "\x{0425}",
- 'Kheicoptic' => "\x{03E6}",
- 'Khook' => "\x{0198}",
- 'Kjecyrillic' => "\x{040C}",
- 'Klinebelow' => "\x{1E34}",
- 'Kmonospace' => "\x{FF2B}",
- 'Koppacyrillic' => "\x{0480}",
- 'Koppagreek' => "\x{03DE}",
- 'Ksicyrillic' => "\x{046E}",
- 'Ksmall' => "\x{F76B}",
- 'LJ' => "\x{01C7}",
- 'LL' => "\x{F6BF}",
- 'Lcedilla' => "\x{013B}",
- 'Lcircle' => "\x{24C1}",
- 'Lcircumflexbelow' => "\x{1E3C}",
- 'Ldotaccent' => "\x{013F}",
- 'Ldotbelow' => "\x{1E36}",
- 'Ldotbelowmacron' => "\x{1E38}",
- 'Liwnarmenian' => "\x{053C}",
- 'Lj' => "\x{01C8}",
- 'Ljecyrillic' => "\x{0409}",
- 'Llinebelow' => "\x{1E3A}",
- 'Lmonospace' => "\x{FF2C}",
- 'Lslashsmall' => "\x{F6F9}",
- 'Lsmall' => "\x{F76C}",
- 'MBsquare' => "\x{3386}",
- 'Macron' => "\x{F6D0}",
- 'Macronsmall' => "\x{F7AF}",
- 'Macute' => "\x{1E3E}",
- 'Mcircle' => "\x{24C2}",
- 'Mdotaccent' => "\x{1E40}",
- 'Mdotbelow' => "\x{1E42}",
- 'Menarmenian' => "\x{0544}",
- 'Mmonospace' => "\x{FF2D}",
- 'Msmall' => "\x{F76D}",
- 'Mturned' => "\x{019C}",
- 'NJ' => "\x{01CA}",
- 'Ncedilla' => "\x{0145}",
- 'Ncircle' => "\x{24C3}",
- 'Ncircumflexbelow' => "\x{1E4A}",
- 'Ndotaccent' => "\x{1E44}",
- 'Ndotbelow' => "\x{1E46}",
- 'Nhookleft' => "\x{019D}",
- 'Nineroman' => "\x{2168}",
- 'Nj' => "\x{01CB}",
- 'Njecyrillic' => "\x{040A}",
- 'Nlinebelow' => "\x{1E48}",
- 'Nmonospace' => "\x{FF2E}",
- 'Nowarmenian' => "\x{0546}",
- 'Nsmall' => "\x{F76E}",
- 'Ntildesmall' => "\x{F7F1}",
- 'OEsmall' => "\x{F6FA}",
- 'Oacutesmall' => "\x{F7F3}",
- 'Obarredcyrillic' => "\x{04E8}",
- 'Obarreddieresiscyrillic' => "\x{04EA}",
- 'Ocaron' => "\x{01D1}",
- 'Ocenteredtilde' => "\x{019F}",
- 'Ocircle' => "\x{24C4}",
- 'Ocircumflexacute' => "\x{1ED0}",
- 'Ocircumflexdotbelow' => "\x{1ED8}",
- 'Ocircumflexgrave' => "\x{1ED2}",
- 'Ocircumflexhookabove' => "\x{1ED4}",
- 'Ocircumflexsmall' => "\x{F7F4}",
- 'Ocircumflextilde' => "\x{1ED6}",
- 'Ocyrillic' => "\x{041E}",
- 'Odblacute' => "\x{0150}",
- 'Odblgrave' => "\x{020C}",
- 'Odieresiscyrillic' => "\x{04E6}",
- 'Odieresissmall' => "\x{F7F6}",
- 'Odotbelow' => "\x{1ECC}",
- 'Ogoneksmall' => "\x{F6FB}",
- 'Ogravesmall' => "\x{F7F2}",
- 'Oharmenian' => "\x{0555}",
- 'Ohm' => "\x{2126}",
- 'Ohookabove' => "\x{1ECE}",
- 'Ohornacute' => "\x{1EDA}",
- 'Ohorndotbelow' => "\x{1EE2}",
- 'Ohorngrave' => "\x{1EDC}",
- 'Ohornhookabove' => "\x{1EDE}",
- 'Ohorntilde' => "\x{1EE0}",
- 'Oi' => "\x{01A2}",
- 'Oinvertedbreve' => "\x{020E}",
- 'Omacronacute' => "\x{1E52}",
- 'Omacrongrave' => "\x{1E50}",
- 'Omegacyrillic' => "\x{0460}",
- 'Omegagreek' => "\x{03A9}",
- 'Omegaroundcyrillic' => "\x{047A}",
- 'Omegatitlocyrillic' => "\x{047C}",
- 'Omonospace' => "\x{FF2F}",
- 'Oneroman' => "\x{2160}",
- 'Oogonek' => "\x{01EA}",
- 'Oogonekmacron' => "\x{01EC}",
- 'Oopen' => "\x{0186}",
- 'Oslashsmall' => "\x{F7F8}",
- 'Osmall' => "\x{F76F}",
- 'Ostrokeacute' => "\x{01FE}",
- 'Otcyrillic' => "\x{047E}",
- 'Otildeacute' => "\x{1E4C}",
- 'Otildedieresis' => "\x{1E4E}",
- 'Otildesmall' => "\x{F7F5}",
- 'Pacute' => "\x{1E54}",
- 'Pcircle' => "\x{24C5}",
- 'Pdotaccent' => "\x{1E56}",
- 'Pecyrillic' => "\x{041F}",
- 'Peharmenian' => "\x{054A}",
- 'Pemiddlehookcyrillic' => "\x{04A6}",
- 'Phook' => "\x{01A4}",
- 'Piwrarmenian' => "\x{0553}",
- 'Pmonospace' => "\x{FF30}",
- 'Psicyrillic' => "\x{0470}",
- 'Psmall' => "\x{F770}",
- 'Qcircle' => "\x{24C6}",
- 'Qmonospace' => "\x{FF31}",
- 'Qsmall' => "\x{F771}",
- 'Raarmenian' => "\x{054C}",
- 'Rcedilla' => "\x{0156}",
- 'Rcircle' => "\x{24C7}",
- 'Rdblgrave' => "\x{0210}",
- 'Rdotaccent' => "\x{1E58}",
- 'Rdotbelow' => "\x{1E5A}",
- 'Rdotbelowmacron' => "\x{1E5C}",
- 'Reharmenian' => "\x{0550}",
- 'Ringsmall' => "\x{F6FC}",
- 'Rinvertedbreve' => "\x{0212}",
- 'Rlinebelow' => "\x{1E5E}",
- 'Rmonospace' => "\x{FF32}",
- 'Rsmall' => "\x{F772}",
- 'Rsmallinverted' => "\x{0281}",
- 'Rsmallinvertedsuperior' => "\x{02B6}",
- 'Sacutedotaccent' => "\x{1E64}",
- 'Sampigreek' => "\x{03E0}",
- 'Scarondotaccent' => "\x{1E66}",
- 'Scaronsmall' => "\x{F6FD}",
- 'Schwa' => "\x{018F}",
- 'Schwacyrillic' => "\x{04D8}",
- 'Schwadieresiscyrillic' => "\x{04DA}",
- 'Scircle' => "\x{24C8}",
- 'Sdotaccent' => "\x{1E60}",
- 'Sdotbelow' => "\x{1E62}",
- 'Sdotbelowdotaccent' => "\x{1E68}",
- 'Seharmenian' => "\x{054D}",
- 'Sevenroman' => "\x{2166}",
- 'Shaarmenian' => "\x{0547}",
- 'Shacyrillic' => "\x{0428}",
- 'Shchacyrillic' => "\x{0429}",
- 'Sheicoptic' => "\x{03E2}",
- 'Shhacyrillic' => "\x{04BA}",
- 'Shimacoptic' => "\x{03EC}",
- 'Sixroman' => "\x{2165}",
- 'Smonospace' => "\x{FF33}",
- 'Softsigncyrillic' => "\x{042C}",
- 'Ssmall' => "\x{F773}",
- 'Stigmagreek' => "\x{03DA}",
- 'Tcedilla' => "\x{0162}",
- 'Tcircle' => "\x{24C9}",
- 'Tcircumflexbelow' => "\x{1E70}",
- 'Tdotaccent' => "\x{1E6A}",
- 'Tdotbelow' => "\x{1E6C}",
- 'Tecyrillic' => "\x{0422}",
- 'Tedescendercyrillic' => "\x{04AC}",
- 'Tenroman' => "\x{2169}",
- 'Tetsecyrillic' => "\x{04B4}",
- 'Thook' => "\x{01AC}",
- 'Thornsmall' => "\x{F7FE}",
- 'Threeroman' => "\x{2162}",
- 'Tildesmall' => "\x{F6FE}",
- 'Tiwnarmenian' => "\x{054F}",
- 'Tlinebelow' => "\x{1E6E}",
- 'Tmonospace' => "\x{FF34}",
- 'Toarmenian' => "\x{0539}",
- 'Tonefive' => "\x{01BC}",
- 'Tonesix' => "\x{0184}",
- 'Tonetwo' => "\x{01A7}",
- 'Tretroflexhook' => "\x{01AE}",
- 'Tsecyrillic' => "\x{0426}",
- 'Tshecyrillic' => "\x{040B}",
- 'Tsmall' => "\x{F774}",
- 'Twelveroman' => "\x{216B}",
- 'Tworoman' => "\x{2161}",
- 'Uacutesmall' => "\x{F7FA}",
- 'Ucaron' => "\x{01D3}",
- 'Ucircle' => "\x{24CA}",
- 'Ucircumflexbelow' => "\x{1E76}",
- 'Ucircumflexsmall' => "\x{F7FB}",
- 'Ucyrillic' => "\x{0423}",
- 'Udblacute' => "\x{0170}",
- 'Udblgrave' => "\x{0214}",
- 'Udieresisacute' => "\x{01D7}",
- 'Udieresisbelow' => "\x{1E72}",
- 'Udieresiscaron' => "\x{01D9}",
- 'Udieresiscyrillic' => "\x{04F0}",
- 'Udieresisgrave' => "\x{01DB}",
- 'Udieresismacron' => "\x{01D5}",
- 'Udieresissmall' => "\x{F7FC}",
- 'Udotbelow' => "\x{1EE4}",
- 'Ugravesmall' => "\x{F7F9}",
- 'Uhookabove' => "\x{1EE6}",
- 'Uhornacute' => "\x{1EE8}",
- 'Uhorndotbelow' => "\x{1EF0}",
- 'Uhorngrave' => "\x{1EEA}",
- 'Uhornhookabove' => "\x{1EEC}",
- 'Uhorntilde' => "\x{1EEE}",
- 'Uhungarumlautcyrillic' => "\x{04F2}",
- 'Uinvertedbreve' => "\x{0216}",
- 'Ukcyrillic' => "\x{0478}",
- 'Umacroncyrillic' => "\x{04EE}",
- 'Umacrondieresis' => "\x{1E7A}",
- 'Umonospace' => "\x{FF35}",
- 'Upsilonacutehooksymbolgreek' => "\x{03D3}",
- 'Upsilonafrican' => "\x{01B1}",
- 'Upsilondieresishooksymbolgreek' => "\x{03D4}",
- 'Upsilonhooksymbol' => "\x{03D2}",
- 'Ushortcyrillic' => "\x{040E}",
- 'Usmall' => "\x{F775}",
- 'Ustraightcyrillic' => "\x{04AE}",
- 'Ustraightstrokecyrillic' => "\x{04B0}",
- 'Utildeacute' => "\x{1E78}",
- 'Utildebelow' => "\x{1E74}",
- 'Vcircle' => "\x{24CB}",
- 'Vdotbelow' => "\x{1E7E}",
- 'Vecyrillic' => "\x{0412}",
- 'Vewarmenian' => "\x{054E}",
- 'Vhook' => "\x{01B2}",
- 'Vmonospace' => "\x{FF36}",
- 'Voarmenian' => "\x{0548}",
- 'Vsmall' => "\x{F776}",
- 'Vtilde' => "\x{1E7C}",
- 'Wcircle' => "\x{24CC}",
- 'Wdotaccent' => "\x{1E86}",
- 'Wdotbelow' => "\x{1E88}",
- 'Wmonospace' => "\x{FF37}",
- 'Wsmall' => "\x{F777}",
- 'Xcircle' => "\x{24CD}",
- 'Xdieresis' => "\x{1E8C}",
- 'Xdotaccent' => "\x{1E8A}",
- 'Xeharmenian' => "\x{053D}",
- 'Xmonospace' => "\x{FF38}",
- 'Xsmall' => "\x{F778}",
- 'Yacutesmall' => "\x{F7FD}",
- 'Yatcyrillic' => "\x{0462}",
- 'Ycircle' => "\x{24CE}",
- 'Ydieresissmall' => "\x{F7FF}",
- 'Ydotaccent' => "\x{1E8E}",
- 'Ydotbelow' => "\x{1EF4}",
- 'Yericyrillic' => "\x{042B}",
- 'Yerudieresiscyrillic' => "\x{04F8}",
- 'Yhook' => "\x{01B3}",
- 'Yhookabove' => "\x{1EF6}",
- 'Yiarmenian' => "\x{0545}",
- 'Yicyrillic' => "\x{0407}",
- 'Yiwnarmenian' => "\x{0552}",
- 'Ymonospace' => "\x{FF39}",
- 'Ysmall' => "\x{F779}",
- 'Ytilde' => "\x{1EF8}",
- 'Yusbigcyrillic' => "\x{046A}",
- 'Yusbigiotifiedcyrillic' => "\x{046C}",
- 'Yuslittlecyrillic' => "\x{0466}",
- 'Yuslittleiotifiedcyrillic' => "\x{0468}",
- 'Zaarmenian' => "\x{0536}",
- 'Zcaronsmall' => "\x{F6FF}",
- 'Zcircle' => "\x{24CF}",
- 'Zcircumflex' => "\x{1E90}",
- 'Zdot' => "\x{017B}",
- 'Zdotbelow' => "\x{1E92}",
- 'Zecyrillic' => "\x{0417}",
- 'Zedescendercyrillic' => "\x{0498}",
- 'Zedieresiscyrillic' => "\x{04DE}",
- 'Zhearmenian' => "\x{053A}",
- 'Zhebrevecyrillic' => "\x{04C1}",
- 'Zhecyrillic' => "\x{0416}",
- 'Zhedescendercyrillic' => "\x{0496}",
- 'Zhedieresiscyrillic' => "\x{04DC}",
- 'Zlinebelow' => "\x{1E94}",
- 'Zmonospace' => "\x{FF3A}",
- 'Zsmall' => "\x{F77A}",
- 'Zstroke' => "\x{01B5}",
- 'aabengali' => "\x{0986}",
- 'aadeva' => "\x{0906}",
- 'aagujarati' => "\x{0A86}",
- 'aagurmukhi' => "\x{0A06}",
- 'aamatragurmukhi' => "\x{0A3E}",
- 'aarusquare' => "\x{3303}",
- 'aavowelsignbengali' => "\x{09BE}",
- 'aavowelsigndeva' => "\x{093E}",
- 'aavowelsigngujarati' => "\x{0ABE}",
- 'abbreviationmarkarmenian' => "\x{055F}",
- 'abbreviationsigndeva' => "\x{0970}",
- 'abengali' => "\x{0985}",
- 'abopomofo' => "\x{311A}",
- 'abreveacute' => "\x{1EAF}",
- 'abrevecyrillic' => "\x{04D1}",
- 'abrevedotbelow' => "\x{1EB7}",
- 'abrevegrave' => "\x{1EB1}",
- 'abrevehookabove' => "\x{1EB3}",
- 'abrevetilde' => "\x{1EB5}",
- 'acaron' => "\x{01CE}",
- 'acircle' => "\x{24D0}",
- 'acircumflexacute' => "\x{1EA5}",
- 'acircumflexdotbelow' => "\x{1EAD}",
- 'acircumflexgrave' => "\x{1EA7}",
- 'acircumflexhookabove' => "\x{1EA9}",
- 'acircumflextilde' => "\x{1EAB}",
- 'acutebelowcmb' => "\x{0317}",
- 'acutecmb' => "\x{0301}",
- 'acutedeva' => "\x{0954}",
- 'acutelowmod' => "\x{02CF}",
- 'acutetonecmb' => "\x{0341}",
- 'acyrillic' => "\x{0430}",
- 'adblgrave' => "\x{0201}",
- 'addakgurmukhi' => "\x{0A71}",
- 'adeva' => "\x{0905}",
- 'adieresiscyrillic' => "\x{04D3}",
- 'adieresismacron' => "\x{01DF}",
- 'adotbelow' => "\x{1EA1}",
- 'adotmacron' => "\x{01E1}",
- 'aekorean' => "\x{3150}",
- 'aemacron' => "\x{01E3}",
- 'afii08941' => "\x{20A4}",
- 'afii10063' => "\x{F6C4}",
- 'afii10064' => "\x{F6C5}",
- 'afii10192' => "\x{F6C6}",
- 'afii10831' => "\x{F6C7}",
- 'afii10832' => "\x{F6C8}",
- 'agujarati' => "\x{0A85}",
- 'agurmukhi' => "\x{0A05}",
- 'ahiragana' => "\x{3042}",
- 'ahookabove' => "\x{1EA3}",
- 'aibengali' => "\x{0990}",
- 'aibopomofo' => "\x{311E}",
- 'aideva' => "\x{0910}",
- 'aiecyrillic' => "\x{04D5}",
- 'aigujarati' => "\x{0A90}",
- 'aigurmukhi' => "\x{0A10}",
- 'aimatragurmukhi' => "\x{0A48}",
- 'ainarabic' => "\x{0639}",
- 'ainfinalarabic' => "\x{FECA}",
- 'aininitialarabic' => "\x{FECB}",
- 'ainmedialarabic' => "\x{FECC}",
- 'ainvertedbreve' => "\x{0203}",
- 'aivowelsignbengali' => "\x{09C8}",
- 'aivowelsigndeva' => "\x{0948}",
- 'aivowelsigngujarati' => "\x{0AC8}",
- 'akatakana' => "\x{30A2}",
- 'akatakanahalfwidth' => "\x{FF71}",
- 'akorean' => "\x{314F}",
- 'alef' => "\x{05D0}",
- 'alefarabic' => "\x{0627}",
- 'alefdageshhebrew' => "\x{FB30}",
- 'aleffinalarabic' => "\x{FE8E}",
- 'alefhamzaabovearabic' => "\x{0623}",
- 'alefhamzaabovefinalarabic' => "\x{FE84}",
- 'alefhamzabelowarabic' => "\x{0625}",
- 'alefhamzabelowfinalarabic' => "\x{FE88}",
- 'alefhebrew' => "\x{05D0}",
- 'aleflamedhebrew' => "\x{FB4F}",
- 'alefmaddaabovearabic' => "\x{0622}",
- 'alefmaddaabovefinalarabic' => "\x{FE82}",
- 'alefmaksuraarabic' => "\x{0649}",
- 'alefmaksurafinalarabic' => "\x{FEF0}",
- 'alefmaksurainitialarabic' => "\x{FEF3}",
- 'alefmaksuramedialarabic' => "\x{FEF4}",
- 'alefpatahhebrew' => "\x{FB2E}",
- 'alefqamatshebrew' => "\x{FB2F}",
- 'allequal' => "\x{224C}",
- 'amonospace' => "\x{FF41}",
- 'ampersandmonospace' => "\x{FF06}",
- 'ampersandsmall' => "\x{F726}",
- 'amsquare' => "\x{33C2}",
- 'anbopomofo' => "\x{3122}",
- 'angbopomofo' => "\x{3124}",
- 'angkhankhuthai' => "\x{0E5A}",
- 'anglebracketleft' => "\x{3008}",
- 'anglebracketleftvertical' => "\x{FE3F}",
- 'anglebracketright' => "\x{3009}",
- 'anglebracketrightvertical' => "\x{FE40}",
- 'angstrom' => "\x{212B}",
- 'anudattadeva' => "\x{0952}",
- 'anusvarabengali' => "\x{0982}",
- 'anusvaradeva' => "\x{0902}",
- 'anusvaragujarati' => "\x{0A82}",
- 'apaatosquare' => "\x{3300}",
- 'aparen' => "\x{249C}",
- 'apostrophearmenian' => "\x{055A}",
- 'apostrophemod' => "\x{02BC}",
- 'apple' => "\x{F8FF}",
- 'approaches' => "\x{2250}",
- 'approxequalorimage' => "\x{2252}",
- 'approximatelyequal' => "\x{2245}",
- 'araeaekorean' => "\x{318E}",
- 'araeakorean' => "\x{318D}",
- 'arc' => "\x{2312}",
- 'arighthalfring' => "\x{1E9A}",
- 'aringbelow' => "\x{1E01}",
- 'arrowdashdown' => "\x{21E3}",
- 'arrowdashleft' => "\x{21E0}",
- 'arrowdashright' => "\x{21E2}",
- 'arrowdashup' => "\x{21E1}",
- 'arrowdownleft' => "\x{2199}",
- 'arrowdownright' => "\x{2198}",
- 'arrowdownwhite' => "\x{21E9}",
- 'arrowheaddownmod' => "\x{02C5}",
- 'arrowheadleftmod' => "\x{02C2}",
- 'arrowheadrightmod' => "\x{02C3}",
- 'arrowheadupmod' => "\x{02C4}",
- 'arrowhorizex' => "\x{F8E7}",
- 'arrowleftdbl' => "\x{21D0}",
- 'arrowleftdblstroke' => "\x{21CD}",
- 'arrowleftoverright' => "\x{21C6}",
- 'arrowleftwhite' => "\x{21E6}",
- 'arrowrightdblstroke' => "\x{21CF}",
- 'arrowrightheavy' => "\x{279E}",
- 'arrowrightoverleft' => "\x{21C4}",
- 'arrowrightwhite' => "\x{21E8}",
- 'arrowtableft' => "\x{21E4}",
- 'arrowtabright' => "\x{21E5}",
- 'arrowupdownbase' => "\x{21A8}",
- 'arrowupleft' => "\x{2196}",
- 'arrowupleftofdown' => "\x{21C5}",
- 'arrowupright' => "\x{2197}",
- 'arrowupwhite' => "\x{21E7}",
- 'arrowvertex' => "\x{F8E6}",
- 'asciicircummonospace' => "\x{FF3E}",
- 'asciitildemonospace' => "\x{FF5E}",
- 'ascript' => "\x{0251}",
- 'ascriptturned' => "\x{0252}",
- 'asmallhiragana' => "\x{3041}",
- 'asmallkatakana' => "\x{30A1}",
- 'asmallkatakanahalfwidth' => "\x{FF67}",
- 'asteriskaltonearabic' => "\x{066D}",
- 'asteriskarabic' => "\x{066D}",
- 'asteriskmonospace' => "\x{FF0A}",
- 'asterisksmall' => "\x{FE61}",
- 'asterism' => "\x{2042}",
- 'asuperior' => "\x{F6E9}",
- 'asymptoticallyequal' => "\x{2243}",
- 'atmonospace' => "\x{FF20}",
- 'atsmall' => "\x{FE6B}",
- 'aturned' => "\x{0250}",
- 'aubengali' => "\x{0994}",
- 'aubopomofo' => "\x{3120}",
- 'audeva' => "\x{0914}",
- 'augujarati' => "\x{0A94}",
- 'augurmukhi' => "\x{0A14}",
- 'aulengthmarkbengali' => "\x{09D7}",
- 'aumatragurmukhi' => "\x{0A4C}",
- 'auvowelsignbengali' => "\x{09CC}",
- 'auvowelsigndeva' => "\x{094C}",
- 'auvowelsigngujarati' => "\x{0ACC}",
- 'avagrahadeva' => "\x{093D}",
- 'aybarmenian' => "\x{0561}",
- 'ayin' => "\x{05E2}",
- 'ayinaltonehebrew' => "\x{FB20}",
- 'ayinhebrew' => "\x{05E2}",
- 'babengali' => "\x{09AC}",
- 'backslashmonospace' => "\x{FF3C}",
- 'badeva' => "\x{092C}",
- 'bagujarati' => "\x{0AAC}",
- 'bagurmukhi' => "\x{0A2C}",
- 'bahiragana' => "\x{3070}",
- 'bahtthai' => "\x{0E3F}",
- 'bakatakana' => "\x{30D0}",
- 'barmonospace' => "\x{FF5C}",
- 'bbopomofo' => "\x{3105}",
- 'bcircle' => "\x{24D1}",
- 'bdotaccent' => "\x{1E03}",
- 'bdotbelow' => "\x{1E05}",
- 'beamedsixteenthnotes' => "\x{266C}",
- 'because' => "\x{2235}",
- 'becyrillic' => "\x{0431}",
- 'beharabic' => "\x{0628}",
- 'behfinalarabic' => "\x{FE90}",
- 'behinitialarabic' => "\x{FE91}",
- 'behiragana' => "\x{3079}",
- 'behmedialarabic' => "\x{FE92}",
- 'behmeeminitialarabic' => "\x{FC9F}",
- 'behmeemisolatedarabic' => "\x{FC08}",
- 'behnoonfinalarabic' => "\x{FC6D}",
- 'bekatakana' => "\x{30D9}",
- 'benarmenian' => "\x{0562}",
- 'bet' => "\x{05D1}",
- 'betasymbolgreek' => "\x{03D0}",
- 'betdagesh' => "\x{FB31}",
- 'betdageshhebrew' => "\x{FB31}",
- 'bethebrew' => "\x{05D1}",
- 'betrafehebrew' => "\x{FB4C}",
- 'bhabengali' => "\x{09AD}",
- 'bhadeva' => "\x{092D}",
- 'bhagujarati' => "\x{0AAD}",
- 'bhagurmukhi' => "\x{0A2D}",
- 'bhook' => "\x{0253}",
- 'bihiragana' => "\x{3073}",
- 'bikatakana' => "\x{30D3}",
- 'bilabialclick' => "\x{0298}",
- 'bindigurmukhi' => "\x{0A02}",
- 'birusquare' => "\x{3331}",
- 'blackcircle' => "\x{25CF}",
- 'blackdiamond' => "\x{25C6}",
- 'blackdownpointingtriangle' => "\x{25BC}",
- 'blackleftpointingpointer' => "\x{25C4}",
- 'blackleftpointingtriangle' => "\x{25C0}",
- 'blacklenticularbracketleft' => "\x{3010}",
- 'blacklenticularbracketleftvertical' => "\x{FE3B}",
- 'blacklenticularbracketright' => "\x{3011}",
- 'blacklenticularbracketrightvertical' => "\x{FE3C}",
- 'blacklowerlefttriangle' => "\x{25E3}",
- 'blacklowerrighttriangle' => "\x{25E2}",
- 'blackrectangle' => "\x{25AC}",
- 'blackrightpointingpointer' => "\x{25BA}",
- 'blackrightpointingtriangle' => "\x{25B6}",
- 'blacksmallsquare' => "\x{25AA}",
- 'blacksmilingface' => "\x{263B}",
- 'blacksquare' => "\x{25A0}",
- 'blackstar' => "\x{2605}",
- 'blackupperlefttriangle' => "\x{25E4}",
- 'blackupperrighttriangle' => "\x{25E5}",
- 'blackuppointingsmalltriangle' => "\x{25B4}",
- 'blackuppointingtriangle' => "\x{25B2}",
- 'blank' => "\x{2423}",
- 'blinebelow' => "\x{1E07}",
- 'bmonospace' => "\x{FF42}",
- 'bobaimaithai' => "\x{0E1A}",
- 'bohiragana' => "\x{307C}",
- 'bokatakana' => "\x{30DC}",
- 'bparen' => "\x{249D}",
- 'bqsquare' => "\x{33C3}",
- 'braceex' => "\x{F8F4}",
- 'braceleftbt' => "\x{F8F3}",
- 'braceleftmid' => "\x{F8F2}",
- 'braceleftmonospace' => "\x{FF5B}",
- 'braceleftsmall' => "\x{FE5B}",
- 'bracelefttp' => "\x{F8F1}",
- 'braceleftvertical' => "\x{FE37}",
- 'bracerightbt' => "\x{F8FE}",
- 'bracerightmid' => "\x{F8FD}",
- 'bracerightmonospace' => "\x{FF5D}",
- 'bracerightsmall' => "\x{FE5C}",
- 'bracerighttp' => "\x{F8FC}",
- 'bracerightvertical' => "\x{FE38}",
- 'bracketleftbt' => "\x{F8F0}",
- 'bracketleftex' => "\x{F8EF}",
- 'bracketleftmonospace' => "\x{FF3B}",
- 'bracketlefttp' => "\x{F8EE}",
- 'bracketrightbt' => "\x{F8FB}",
- 'bracketrightex' => "\x{F8FA}",
- 'bracketrightmonospace' => "\x{FF3D}",
- 'bracketrighttp' => "\x{F8F9}",
- 'brevebelowcmb' => "\x{032E}",
- 'brevecmb' => "\x{0306}",
- 'breveinvertedbelowcmb' => "\x{032F}",
- 'breveinvertedcmb' => "\x{0311}",
- 'breveinverteddoublecmb' => "\x{0361}",
- 'bridgebelowcmb' => "\x{032A}",
- 'bridgeinvertedbelowcmb' => "\x{033A}",
- 'bstroke' => "\x{0180}",
- 'bsuperior' => "\x{F6EA}",
- 'btopbar' => "\x{0183}",
- 'buhiragana' => "\x{3076}",
- 'bukatakana' => "\x{30D6}",
- 'bulletinverse' => "\x{25D8}",
- 'bulletoperator' => "\x{2219}",
- 'bullseye' => "\x{25CE}",
- 'caarmenian' => "\x{056E}",
- 'cabengali' => "\x{099A}",
- 'cadeva' => "\x{091A}",
- 'cagujarati' => "\x{0A9A}",
- 'cagurmukhi' => "\x{0A1A}",
- 'calsquare' => "\x{3388}",
- 'candrabindubengali' => "\x{0981}",
- 'candrabinducmb' => "\x{0310}",
- 'candrabindudeva' => "\x{0901}",
- 'candrabindugujarati' => "\x{0A81}",
- 'capslock' => "\x{21EA}",
- 'careof' => "\x{2105}",
- 'caronbelowcmb' => "\x{032C}",
- 'caroncmb' => "\x{030C}",
- 'cbopomofo' => "\x{3118}",
- 'ccedillaacute' => "\x{1E09}",
- 'ccircle' => "\x{24D2}",
- 'ccurl' => "\x{0255}",
- 'cdot' => "\x{010B}",
- 'cdsquare' => "\x{33C5}",
- 'cedillacmb' => "\x{0327}",
- 'centigrade' => "\x{2103}",
- 'centinferior' => "\x{F6DF}",
- 'centmonospace' => "\x{FFE0}",
- 'centoldstyle' => "\x{F7A2}",
- 'centsuperior' => "\x{F6E0}",
- 'chaarmenian' => "\x{0579}",
- 'chabengali' => "\x{099B}",
- 'chadeva' => "\x{091B}",
- 'chagujarati' => "\x{0A9B}",
- 'chagurmukhi' => "\x{0A1B}",
- 'chbopomofo' => "\x{3114}",
- 'cheabkhasiancyrillic' => "\x{04BD}",
- 'checkmark' => "\x{2713}",
- 'checyrillic' => "\x{0447}",
- 'chedescenderabkhasiancyrillic' => "\x{04BF}",
- 'chedescendercyrillic' => "\x{04B7}",
- 'chedieresiscyrillic' => "\x{04F5}",
- 'cheharmenian' => "\x{0573}",
- 'chekhakassiancyrillic' => "\x{04CC}",
- 'cheverticalstrokecyrillic' => "\x{04B9}",
- 'chieuchacirclekorean' => "\x{3277}",
- 'chieuchaparenkorean' => "\x{3217}",
- 'chieuchcirclekorean' => "\x{3269}",
- 'chieuchkorean' => "\x{314A}",
- 'chieuchparenkorean' => "\x{3209}",
- 'chochangthai' => "\x{0E0A}",
- 'chochanthai' => "\x{0E08}",
- 'chochingthai' => "\x{0E09}",
- 'chochoethai' => "\x{0E0C}",
- 'chook' => "\x{0188}",
- 'cieucacirclekorean' => "\x{3276}",
- 'cieucaparenkorean' => "\x{3216}",
- 'cieuccirclekorean' => "\x{3268}",
- 'cieuckorean' => "\x{3148}",
- 'cieucparenkorean' => "\x{3208}",
- 'cieucuparenkorean' => "\x{321C}",
- 'circleot' => "\x{2299}",
- 'circlepostalmark' => "\x{3036}",
- 'circlewithlefthalfblack' => "\x{25D0}",
- 'circlewithrighthalfblack' => "\x{25D1}",
- 'circumflexbelowcmb' => "\x{032D}",
- 'circumflexcmb' => "\x{0302}",
- 'clear' => "\x{2327}",
- 'clickalveolar' => "\x{01C2}",
- 'clickdental' => "\x{01C0}",
- 'clicklateral' => "\x{01C1}",
- 'clickretroflex' => "\x{01C3}",
- 'clubsuitblack' => "\x{2663}",
- 'clubsuitwhite' => "\x{2667}",
- 'cmcubedsquare' => "\x{33A4}",
- 'cmonospace' => "\x{FF43}",
- 'cmsquaredsquare' => "\x{33A0}",
- 'coarmenian' => "\x{0581}",
- 'colonmonospace' => "\x{FF1A}",
- 'colonsign' => "\x{20A1}",
- 'colonsmall' => "\x{FE55}",
- 'colontriangularhalfmod' => "\x{02D1}",
- 'colontriangularmod' => "\x{02D0}",
- 'commaabovecmb' => "\x{0313}",
- 'commaaboverightcmb' => "\x{0315}",
- 'commaaccent' => "\x{F6C3}",
- 'commaarabic' => "\x{060C}",
- 'commaarmenian' => "\x{055D}",
- 'commainferior' => "\x{F6E1}",
- 'commamonospace' => "\x{FF0C}",
- 'commareversedabovecmb' => "\x{0314}",
- 'commareversedmod' => "\x{02BD}",
- 'commasmall' => "\x{FE50}",
- 'commasuperior' => "\x{F6E2}",
- 'commaturnedabovecmb' => "\x{0312}",
- 'commaturnedmod' => "\x{02BB}",
- 'compass' => "\x{263C}",
- 'contourintegral' => "\x{222E}",
- 'control' => "\x{2303}",
- 'controlACK' => "\x{0006}",
- 'controlBEL' => "\x{0007}",
- 'controlBS' => "\x{0008}",
- 'controlCAN' => "\x{0018}",
- 'controlCR' => "\x{000D}",
- 'controlDC1' => "\x{0011}",
- 'controlDC2' => "\x{0012}",
- 'controlDC3' => "\x{0013}",
- 'controlDC4' => "\x{0014}",
- 'controlDEL' => "\x{007F}",
- 'controlDLE' => "\x{0010}",
- 'controlEM' => "\x{0019}",
- 'controlENQ' => "\x{0005}",
- 'controlEOT' => "\x{0004}",
- 'controlESC' => "\x{001B}",
- 'controlETB' => "\x{0017}",
- 'controlETX' => "\x{0003}",
- 'controlFF' => "\x{000C}",
- 'controlFS' => "\x{001C}",
- 'controlGS' => "\x{001D}",
- 'controlHT' => "\x{0009}",
- 'controlLF' => "\x{000A}",
- 'controlNAK' => "\x{0015}",
- 'controlRS' => "\x{001E}",
- 'controlSI' => "\x{000F}",
- 'controlSO' => "\x{000E}",
- 'controlSOT' => "\x{0002}",
- 'controlSTX' => "\x{0001}",
- 'controlSUB' => "\x{001A}",
- 'controlSYN' => "\x{0016}",
- 'controlUS' => "\x{001F}",
- 'controlVT' => "\x{000B}",
- 'copyrightsans' => "\x{F8E9}",
- 'copyrightserif' => "\x{F6D9}",
- 'cornerbracketleft' => "\x{300C}",
- 'cornerbracketlefthalfwidth' => "\x{FF62}",
- 'cornerbracketleftvertical' => "\x{FE41}",
- 'cornerbracketright' => "\x{300D}",
- 'cornerbracketrighthalfwidth' => "\x{FF63}",
- 'cornerbracketrightvertical' => "\x{FE42}",
- 'corporationsquare' => "\x{337F}",
- 'cosquare' => "\x{33C7}",
- 'coverkgsquare' => "\x{33C6}",
- 'cparen' => "\x{249E}",
- 'cruzeiro' => "\x{20A2}",
- 'cstretched' => "\x{0297}",
- 'curlyand' => "\x{22CF}",
- 'curlyor' => "\x{22CE}",
- 'cyrBreve' => "\x{F6D1}",
- 'cyrFlex' => "\x{F6D2}",
- 'cyrbreve' => "\x{F6D4}",
- 'cyrflex' => "\x{F6D5}",
- 'daarmenian' => "\x{0564}",
- 'dabengali' => "\x{09A6}",
- 'dadarabic' => "\x{0636}",
- 'dadeva' => "\x{0926}",
- 'dadfinalarabic' => "\x{FEBE}",
- 'dadinitialarabic' => "\x{FEBF}",
- 'dadmedialarabic' => "\x{FEC0}",
- 'dagesh' => "\x{05BC}",
- 'dageshhebrew' => "\x{05BC}",
- 'dagujarati' => "\x{0AA6}",
- 'dagurmukhi' => "\x{0A26}",
- 'dahiragana' => "\x{3060}",
- 'dakatakana' => "\x{30C0}",
- 'dalarabic' => "\x{062F}",
- 'dalet' => "\x{05D3}",
- 'daletdagesh' => "\x{FB33}",
- 'daletdageshhebrew' => "\x{FB33}",
- 'dalethatafpatah' => "\x{05D3}\x{05B2}",
- 'dalethatafpatahhebrew' => "\x{05D3}\x{05B2}",
- 'dalethatafsegol' => "\x{05D3}\x{05B1}",
- 'dalethatafsegolhebrew' => "\x{05D3}\x{05B1}",
- 'dalethebrew' => "\x{05D3}",
- 'dalethiriq' => "\x{05D3}\x{05B4}",
- 'dalethiriqhebrew' => "\x{05D3}\x{05B4}",
- 'daletholam' => "\x{05D3}\x{05B9}",
- 'daletholamhebrew' => "\x{05D3}\x{05B9}",
- 'daletpatah' => "\x{05D3}\x{05B7}",
- 'daletpatahhebrew' => "\x{05D3}\x{05B7}",
- 'daletqamats' => "\x{05D3}\x{05B8}",
- 'daletqamatshebrew' => "\x{05D3}\x{05B8}",
- 'daletqubuts' => "\x{05D3}\x{05BB}",
- 'daletqubutshebrew' => "\x{05D3}\x{05BB}",
- 'daletsegol' => "\x{05D3}\x{05B6}",
- 'daletsegolhebrew' => "\x{05D3}\x{05B6}",
- 'daletsheva' => "\x{05D3}\x{05B0}",
- 'daletshevahebrew' => "\x{05D3}\x{05B0}",
- 'dalettsere' => "\x{05D3}\x{05B5}",
- 'dalettserehebrew' => "\x{05D3}\x{05B5}",
- 'dalfinalarabic' => "\x{FEAA}",
- 'dammaarabic' => "\x{064F}",
- 'dammalowarabic' => "\x{064F}",
- 'dammatanaltonearabic' => "\x{064C}",
- 'dammatanarabic' => "\x{064C}",
- 'danda' => "\x{0964}",
- 'dargahebrew' => "\x{05A7}",
- 'dargalefthebrew' => "\x{05A7}",
- 'dasiapneumatacyrilliccmb' => "\x{0485}",
- 'dblGrave' => "\x{F6D3}",
- 'dblanglebracketleft' => "\x{300A}",
- 'dblanglebracketleftvertical' => "\x{FE3D}",
- 'dblanglebracketright' => "\x{300B}",
- 'dblanglebracketrightvertical' => "\x{FE3E}",
- 'dblarchinvertedbelowcmb' => "\x{032B}",
- 'dblarrowleft' => "\x{21D4}",
- 'dblarrowright' => "\x{21D2}",
- 'dbldanda' => "\x{0965}",
- 'dblgrave' => "\x{F6D6}",
- 'dblgravecmb' => "\x{030F}",
- 'dblintegral' => "\x{222C}",
- 'dbllowline' => "\x{2017}",
- 'dbllowlinecmb' => "\x{0333}",
- 'dbloverlinecmb' => "\x{033F}",
- 'dblprimemod' => "\x{02BA}",
- 'dblverticalbar' => "\x{2016}",
- 'dblverticallineabovecmb' => "\x{030E}",
- 'dbopomofo' => "\x{3109}",
- 'dbsquare' => "\x{33C8}",
- 'dcedilla' => "\x{1E11}",
- 'dcircle' => "\x{24D3}",
- 'dcircumflexbelow' => "\x{1E13}",
- 'ddabengali' => "\x{09A1}",
- 'ddadeva' => "\x{0921}",
- 'ddagujarati' => "\x{0AA1}",
- 'ddagurmukhi' => "\x{0A21}",
- 'ddalarabic' => "\x{0688}",
- 'ddalfinalarabic' => "\x{FB89}",
- 'dddhadeva' => "\x{095C}",
- 'ddhabengali' => "\x{09A2}",
- 'ddhadeva' => "\x{0922}",
- 'ddhagujarati' => "\x{0AA2}",
- 'ddhagurmukhi' => "\x{0A22}",
- 'ddotaccent' => "\x{1E0B}",
- 'ddotbelow' => "\x{1E0D}",
- 'decimalseparatorarabic' => "\x{066B}",
- 'decimalseparatorpersian' => "\x{066B}",
- 'decyrillic' => "\x{0434}",
- 'dehihebrew' => "\x{05AD}",
- 'dehiragana' => "\x{3067}",
- 'deicoptic' => "\x{03EF}",
- 'dekatakana' => "\x{30C7}",
- 'deleteleft' => "\x{232B}",
- 'deleteright' => "\x{2326}",
- 'deltaturned' => "\x{018D}",
- 'denominatorminusonenumeratorbengali' => "\x{09F8}",
- 'dezh' => "\x{02A4}",
- 'dhabengali' => "\x{09A7}",
- 'dhadeva' => "\x{0927}",
- 'dhagujarati' => "\x{0AA7}",
- 'dhagurmukhi' => "\x{0A27}",
- 'dhook' => "\x{0257}",
- 'dialytikatonos' => "\x{0385}",
- 'dialytikatonoscmb' => "\x{0344}",
- 'diamondsuitwhite' => "\x{2662}",
- 'dieresisacute' => "\x{F6D7}",
- 'dieresisbelowcmb' => "\x{0324}",
- 'dieresiscmb' => "\x{0308}",
- 'dieresisgrave' => "\x{F6D8}",
- 'dihiragana' => "\x{3062}",
- 'dikatakana' => "\x{30C2}",
- 'dittomark' => "\x{3003}",
- 'divides' => "\x{2223}",
- 'divisionslash' => "\x{2215}",
- 'djecyrillic' => "\x{0452}",
- 'dlinebelow' => "\x{1E0F}",
- 'dlsquare' => "\x{3397}",
- 'dmacron' => "\x{0111}",
- 'dmonospace' => "\x{FF44}",
- 'dochadathai' => "\x{0E0E}",
- 'dodekthai' => "\x{0E14}",
- 'dohiragana' => "\x{3069}",
- 'dokatakana' => "\x{30C9}",
- 'dollarinferior' => "\x{F6E3}",
- 'dollarmonospace' => "\x{FF04}",
- 'dollaroldstyle' => "\x{F724}",
- 'dollarsmall' => "\x{FE69}",
- 'dollarsuperior' => "\x{F6E4}",
- 'dorusquare' => "\x{3326}",
- 'dotaccentcmb' => "\x{0307}",
- 'dotbelowcmb' => "\x{0323}",
- 'dotkatakana' => "\x{30FB}",
- 'dotlessj' => "\x{F6BE}",
- 'dotlessjstrokehook' => "\x{0284}",
- 'dottedcircle' => "\x{25CC}",
- 'doubleyodpatah' => "\x{FB1F}",
- 'doubleyodpatahhebrew' => "\x{FB1F}",
- 'downtackbelowcmb' => "\x{031E}",
- 'downtackmod' => "\x{02D5}",
- 'dparen' => "\x{249F}",
- 'dsuperior' => "\x{F6EB}",
- 'dtail' => "\x{0256}",
- 'dtopbar' => "\x{018C}",
- 'duhiragana' => "\x{3065}",
- 'dukatakana' => "\x{30C5}",
- 'dz' => "\x{01F3}",
- 'dzaltone' => "\x{02A3}",
- 'dzcaron' => "\x{01C6}",
- 'dzcurl' => "\x{02A5}",
- 'dzeabkhasiancyrillic' => "\x{04E1}",
- 'dzecyrillic' => "\x{0455}",
- 'dzhecyrillic' => "\x{045F}",
- 'earth' => "\x{2641}",
- 'ebengali' => "\x{098F}",
- 'ebopomofo' => "\x{311C}",
- 'ecandradeva' => "\x{090D}",
- 'ecandragujarati' => "\x{0A8D}",
- 'ecandravowelsigndeva' => "\x{0945}",
- 'ecandravowelsigngujarati' => "\x{0AC5}",
- 'ecedillabreve' => "\x{1E1D}",
- 'echarmenian' => "\x{0565}",
- 'echyiwnarmenian' => "\x{0587}",
- 'ecircle' => "\x{24D4}",
- 'ecircumflexacute' => "\x{1EBF}",
- 'ecircumflexbelow' => "\x{1E19}",
- 'ecircumflexdotbelow' => "\x{1EC7}",
- 'ecircumflexgrave' => "\x{1EC1}",
- 'ecircumflexhookabove' => "\x{1EC3}",
- 'ecircumflextilde' => "\x{1EC5}",
- 'ecyrillic' => "\x{0454}",
- 'edblgrave' => "\x{0205}",
- 'edeva' => "\x{090F}",
- 'edot' => "\x{0117}",
- 'edotbelow' => "\x{1EB9}",
- 'eegurmukhi' => "\x{0A0F}",
- 'eematragurmukhi' => "\x{0A47}",
- 'efcyrillic' => "\x{0444}",
- 'egujarati' => "\x{0A8F}",
- 'eharmenian' => "\x{0567}",
- 'ehbopomofo' => "\x{311D}",
- 'ehiragana' => "\x{3048}",
- 'ehookabove' => "\x{1EBB}",
- 'eibopomofo' => "\x{311F}",
- 'eightarabic' => "\x{0668}",
- 'eightbengali' => "\x{09EE}",
- 'eightcircle' => "\x{2467}",
- 'eightcircleinversesansserif' => "\x{2791}",
- 'eightdeva' => "\x{096E}",
- 'eighteencircle' => "\x{2471}",
- 'eighteenparen' => "\x{2485}",
- 'eighteenperiod' => "\x{2499}",
- 'eightgujarati' => "\x{0AEE}",
- 'eightgurmukhi' => "\x{0A6E}",
- 'eighthackarabic' => "\x{0668}",
- 'eighthangzhou' => "\x{3028}",
- 'eighthnotebeamed' => "\x{266B}",
- 'eightideographicparen' => "\x{3227}",
- 'eightinferior' => "\x{2088}",
- 'eightmonospace' => "\x{FF18}",
- 'eightoldstyle' => "\x{F738}",
- 'eightparen' => "\x{247B}",
- 'eightperiod' => "\x{248F}",
- 'eightpersian' => "\x{06F8}",
- 'eightroman' => "\x{2177}",
- 'eightsuperior' => "\x{2078}",
- 'eightthai' => "\x{0E58}",
- 'einvertedbreve' => "\x{0207}",
- 'eiotifiedcyrillic' => "\x{0465}",
- 'ekatakana' => "\x{30A8}",
- 'ekatakanahalfwidth' => "\x{FF74}",
- 'ekonkargurmukhi' => "\x{0A74}",
- 'ekorean' => "\x{3154}",
- 'elcyrillic' => "\x{043B}",
- 'elevencircle' => "\x{246A}",
- 'elevenparen' => "\x{247E}",
- 'elevenperiod' => "\x{2492}",
- 'elevenroman' => "\x{217A}",
- 'ellipsisvertical' => "\x{22EE}",
- 'emacronacute' => "\x{1E17}",
- 'emacrongrave' => "\x{1E15}",
- 'emcyrillic' => "\x{043C}",
- 'emdashvertical' => "\x{FE31}",
- 'emonospace' => "\x{FF45}",
- 'emphasismarkarmenian' => "\x{055B}",
- 'enbopomofo' => "\x{3123}",
- 'encyrillic' => "\x{043D}",
- 'endashvertical' => "\x{FE32}",
- 'endescendercyrillic' => "\x{04A3}",
- 'engbopomofo' => "\x{3125}",
- 'enghecyrillic' => "\x{04A5}",
- 'enhookcyrillic' => "\x{04C8}",
- 'enspace' => "\x{2002}",
- 'eokorean' => "\x{3153}",
- 'eopen' => "\x{025B}",
- 'eopenclosed' => "\x{029A}",
- 'eopenreversed' => "\x{025C}",
- 'eopenreversedclosed' => "\x{025E}",
- 'eopenreversedhook' => "\x{025D}",
- 'eparen' => "\x{24A0}",
- 'equalmonospace' => "\x{FF1D}",
- 'equalsmall' => "\x{FE66}",
- 'equalsuperior' => "\x{207C}",
- 'erbopomofo' => "\x{3126}",
- 'ercyrillic' => "\x{0440}",
- 'ereversed' => "\x{0258}",
- 'ereversedcyrillic' => "\x{044D}",
- 'escyrillic' => "\x{0441}",
- 'esdescendercyrillic' => "\x{04AB}",
- 'esh' => "\x{0283}",
- 'eshcurl' => "\x{0286}",
- 'eshortdeva' => "\x{090E}",
- 'eshortvowelsigndeva' => "\x{0946}",
- 'eshreversedloop' => "\x{01AA}",
- 'eshsquatreversed' => "\x{0285}",
- 'esmallhiragana' => "\x{3047}",
- 'esmallkatakana' => "\x{30A7}",
- 'esmallkatakanahalfwidth' => "\x{FF6A}",
- 'esuperior' => "\x{F6EC}",
- 'etarmenian' => "\x{0568}",
- 'etilde' => "\x{1EBD}",
- 'etildebelow' => "\x{1E1B}",
- 'etnahtafoukhhebrew' => "\x{0591}",
- 'etnahtafoukhlefthebrew' => "\x{0591}",
- 'etnahtahebrew' => "\x{0591}",
- 'etnahtalefthebrew' => "\x{0591}",
- 'eturned' => "\x{01DD}",
- 'eukorean' => "\x{3161}",
- 'euro' => "\x{20AC}",
- 'evowelsignbengali' => "\x{09C7}",
- 'evowelsigndeva' => "\x{0947}",
- 'evowelsigngujarati' => "\x{0AC7}",
- 'exclamarmenian' => "\x{055C}",
- 'exclamdownsmall' => "\x{F7A1}",
- 'exclammonospace' => "\x{FF01}",
- 'exclamsmall' => "\x{F721}",
- 'ezh' => "\x{0292}",
- 'ezhcaron' => "\x{01EF}",
- 'ezhcurl' => "\x{0293}",
- 'ezhreversed' => "\x{01B9}",
- 'ezhtail' => "\x{01BA}",
- 'fadeva' => "\x{095E}",
- 'fagurmukhi' => "\x{0A5E}",
- 'fahrenheit' => "\x{2109}",
- 'fathaarabic' => "\x{064E}",
- 'fathalowarabic' => "\x{064E}",
- 'fathatanarabic' => "\x{064B}",
- 'fbopomofo' => "\x{3108}",
- 'fcircle' => "\x{24D5}",
- 'fdotaccent' => "\x{1E1F}",
- 'feharabic' => "\x{0641}",
- 'feharmenian' => "\x{0586}",
- 'fehfinalarabic' => "\x{FED2}",
- 'fehinitialarabic' => "\x{FED3}",
- 'fehmedialarabic' => "\x{FED4}",
- 'feicoptic' => "\x{03E5}",
- 'fifteencircle' => "\x{246E}",
- 'fifteenparen' => "\x{2482}",
- 'fifteenperiod' => "\x{2496}",
- 'finalkaf' => "\x{05DA}",
- 'finalkafdagesh' => "\x{FB3A}",
- 'finalkafdageshhebrew' => "\x{FB3A}",
- 'finalkafhebrew' => "\x{05DA}",
- 'finalkafqamats' => "\x{05DA}\x{05B8}",
- 'finalkafqamatshebrew' => "\x{05DA}\x{05B8}",
- 'finalkafsheva' => "\x{05DA}\x{05B0}",
- 'finalkafshevahebrew' => "\x{05DA}\x{05B0}",
- 'finalmem' => "\x{05DD}",
- 'finalmemhebrew' => "\x{05DD}",
- 'finalnun' => "\x{05DF}",
- 'finalnunhebrew' => "\x{05DF}",
- 'finalpe' => "\x{05E3}",
- 'finalpehebrew' => "\x{05E3}",
- 'finaltsadi' => "\x{05E5}",
- 'finaltsadihebrew' => "\x{05E5}",
- 'firsttonechinese' => "\x{02C9}",
- 'fisheye' => "\x{25C9}",
- 'fitacyrillic' => "\x{0473}",
- 'fivearabic' => "\x{0665}",
- 'fivebengali' => "\x{09EB}",
- 'fivecircle' => "\x{2464}",
- 'fivecircleinversesansserif' => "\x{278E}",
- 'fivedeva' => "\x{096B}",
- 'fivegujarati' => "\x{0AEB}",
- 'fivegurmukhi' => "\x{0A6B}",
- 'fivehackarabic' => "\x{0665}",
- 'fivehangzhou' => "\x{3025}",
- 'fiveideographicparen' => "\x{3224}",
- 'fiveinferior' => "\x{2085}",
- 'fivemonospace' => "\x{FF15}",
- 'fiveoldstyle' => "\x{F735}",
- 'fiveparen' => "\x{2478}",
- 'fiveperiod' => "\x{248C}",
- 'fivepersian' => "\x{06F5}",
- 'fiveroman' => "\x{2174}",
- 'fivesuperior' => "\x{2075}",
- 'fivethai' => "\x{0E55}",
- 'fmonospace' => "\x{FF46}",
- 'fmsquare' => "\x{3399}",
- 'fofanthai' => "\x{0E1F}",
- 'fofathai' => "\x{0E1D}",
- 'fongmanthai' => "\x{0E4F}",
- 'forall' => "\x{2200}",
- 'fourarabic' => "\x{0664}",
- 'fourbengali' => "\x{09EA}",
- 'fourcircle' => "\x{2463}",
- 'fourcircleinversesansserif' => "\x{278D}",
- 'fourdeva' => "\x{096A}",
- 'fourgujarati' => "\x{0AEA}",
- 'fourgurmukhi' => "\x{0A6A}",
- 'fourhackarabic' => "\x{0664}",
- 'fourhangzhou' => "\x{3024}",
- 'fourideographicparen' => "\x{3223}",
- 'fourinferior' => "\x{2084}",
- 'fourmonospace' => "\x{FF14}",
- 'fournumeratorbengali' => "\x{09F7}",
- 'fouroldstyle' => "\x{F734}",
- 'fourparen' => "\x{2477}",
- 'fourperiod' => "\x{248B}",
- 'fourpersian' => "\x{06F4}",
- 'fourroman' => "\x{2173}",
- 'foursuperior' => "\x{2074}",
- 'fourteencircle' => "\x{246D}",
- 'fourteenparen' => "\x{2481}",
- 'fourteenperiod' => "\x{2495}",
- 'fourthai' => "\x{0E54}",
- 'fourthtonechinese' => "\x{02CB}",
- 'fparen' => "\x{24A1}",
- 'gabengali' => "\x{0997}",
- 'gacute' => "\x{01F5}",
- 'gadeva' => "\x{0917}",
- 'gafarabic' => "\x{06AF}",
- 'gaffinalarabic' => "\x{FB93}",
- 'gafinitialarabic' => "\x{FB94}",
- 'gafmedialarabic' => "\x{FB95}",
- 'gagujarati' => "\x{0A97}",
- 'gagurmukhi' => "\x{0A17}",
- 'gahiragana' => "\x{304C}",
- 'gakatakana' => "\x{30AC}",
- 'gammalatinsmall' => "\x{0263}",
- 'gammasuperior' => "\x{02E0}",
- 'gangiacoptic' => "\x{03EB}",
- 'gbopomofo' => "\x{310D}",
- 'gcedilla' => "\x{0123}",
- 'gcircle' => "\x{24D6}",
- 'gdot' => "\x{0121}",
- 'gecyrillic' => "\x{0433}",
- 'gehiragana' => "\x{3052}",
- 'gekatakana' => "\x{30B2}",
- 'geometricallyequal' => "\x{2251}",
- 'gereshaccenthebrew' => "\x{059C}",
- 'gereshhebrew' => "\x{05F3}",
- 'gereshmuqdamhebrew' => "\x{059D}",
- 'gershayimaccenthebrew' => "\x{059E}",
- 'gershayimhebrew' => "\x{05F4}",
- 'getamark' => "\x{3013}",
- 'ghabengali' => "\x{0998}",
- 'ghadarmenian' => "\x{0572}",
- 'ghadeva' => "\x{0918}",
- 'ghagujarati' => "\x{0A98}",
- 'ghagurmukhi' => "\x{0A18}",
- 'ghainarabic' => "\x{063A}",
- 'ghainfinalarabic' => "\x{FECE}",
- 'ghaininitialarabic' => "\x{FECF}",
- 'ghainmedialarabic' => "\x{FED0}",
- 'ghemiddlehookcyrillic' => "\x{0495}",
- 'ghestrokecyrillic' => "\x{0493}",
- 'gheupturncyrillic' => "\x{0491}",
- 'ghhadeva' => "\x{095A}",
- 'ghhagurmukhi' => "\x{0A5A}",
- 'ghook' => "\x{0260}",
- 'ghzsquare' => "\x{3393}",
- 'gihiragana' => "\x{304E}",
- 'gikatakana' => "\x{30AE}",
- 'gimarmenian' => "\x{0563}",
- 'gimel' => "\x{05D2}",
- 'gimeldagesh' => "\x{FB32}",
- 'gimeldageshhebrew' => "\x{FB32}",
- 'gimelhebrew' => "\x{05D2}",
- 'gjecyrillic' => "\x{0453}",
- 'glottalinvertedstroke' => "\x{01BE}",
- 'glottalstop' => "\x{0294}",
- 'glottalstopinverted' => "\x{0296}",
- 'glottalstopmod' => "\x{02C0}",
- 'glottalstopreversed' => "\x{0295}",
- 'glottalstopreversedmod' => "\x{02C1}",
- 'glottalstopreversedsuperior' => "\x{02E4}",
- 'glottalstopstroke' => "\x{02A1}",
- 'glottalstopstrokereversed' => "\x{02A2}",
- 'gmacron' => "\x{1E21}",
- 'gmonospace' => "\x{FF47}",
- 'gohiragana' => "\x{3054}",
- 'gokatakana' => "\x{30B4}",
- 'gparen' => "\x{24A2}",
- 'gpasquare' => "\x{33AC}",
- 'gravebelowcmb' => "\x{0316}",
- 'gravecmb' => "\x{0300}",
- 'gravedeva' => "\x{0953}",
- 'gravelowmod' => "\x{02CE}",
- 'gravemonospace' => "\x{FF40}",
- 'gravetonecmb' => "\x{0340}",
- 'greaterequalorless' => "\x{22DB}",
- 'greatermonospace' => "\x{FF1E}",
- 'greaterorequivalent' => "\x{2273}",
- 'greaterorless' => "\x{2277}",
- 'greateroverequal' => "\x{2267}",
- 'greatersmall' => "\x{FE65}",
- 'gscript' => "\x{0261}",
- 'gstroke' => "\x{01E5}",
- 'guhiragana' => "\x{3050}",
- 'gukatakana' => "\x{30B0}",
- 'guramusquare' => "\x{3318}",
- 'gysquare' => "\x{33C9}",
- 'haabkhasiancyrillic' => "\x{04A9}",
- 'haaltonearabic' => "\x{06C1}",
- 'habengali' => "\x{09B9}",
- 'hadescendercyrillic' => "\x{04B3}",
- 'hadeva' => "\x{0939}",
- 'hagujarati' => "\x{0AB9}",
- 'hagurmukhi' => "\x{0A39}",
- 'haharabic' => "\x{062D}",
- 'hahfinalarabic' => "\x{FEA2}",
- 'hahinitialarabic' => "\x{FEA3}",
- 'hahiragana' => "\x{306F}",
- 'hahmedialarabic' => "\x{FEA4}",
- 'haitusquare' => "\x{332A}",
- 'hakatakana' => "\x{30CF}",
- 'hakatakanahalfwidth' => "\x{FF8A}",
- 'halantgurmukhi' => "\x{0A4D}",
- 'hamzaarabic' => "\x{0621}",
- 'hamzadammaarabic' => "\x{0621}\x{064F}",
- 'hamzadammatanarabic' => "\x{0621}\x{064C}",
- 'hamzafathaarabic' => "\x{0621}\x{064E}",
- 'hamzafathatanarabic' => "\x{0621}\x{064B}",
- 'hamzalowarabic' => "\x{0621}",
- 'hamzalowkasraarabic' => "\x{0621}\x{0650}",
- 'hamzalowkasratanarabic' => "\x{0621}\x{064D}",
- 'hamzasukunarabic' => "\x{0621}\x{0652}",
- 'hangulfiller' => "\x{3164}",
- 'hardsigncyrillic' => "\x{044A}",
- 'harpoonleftbarbup' => "\x{21BC}",
- 'harpoonrightbarbup' => "\x{21C0}",
- 'hasquare' => "\x{33CA}",
- 'hatafpatah' => "\x{05B2}",
- 'hatafpatah16' => "\x{05B2}",
- 'hatafpatah23' => "\x{05B2}",
- 'hatafpatah2f' => "\x{05B2}",
- 'hatafpatahhebrew' => "\x{05B2}",
- 'hatafpatahnarrowhebrew' => "\x{05B2}",
- 'hatafpatahquarterhebrew' => "\x{05B2}",
- 'hatafpatahwidehebrew' => "\x{05B2}",
- 'hatafqamats' => "\x{05B3}",
- 'hatafqamats1b' => "\x{05B3}",
- 'hatafqamats28' => "\x{05B3}",
- 'hatafqamats34' => "\x{05B3}",
- 'hatafqamatshebrew' => "\x{05B3}",
- 'hatafqamatsnarrowhebrew' => "\x{05B3}",
- 'hatafqamatsquarterhebrew' => "\x{05B3}",
- 'hatafqamatswidehebrew' => "\x{05B3}",
- 'hatafsegol' => "\x{05B1}",
- 'hatafsegol17' => "\x{05B1}",
- 'hatafsegol24' => "\x{05B1}",
- 'hatafsegol30' => "\x{05B1}",
- 'hatafsegolhebrew' => "\x{05B1}",
- 'hatafsegolnarrowhebrew' => "\x{05B1}",
- 'hatafsegolquarterhebrew' => "\x{05B1}",
- 'hatafsegolwidehebrew' => "\x{05B1}",
- 'hbopomofo' => "\x{310F}",
- 'hbrevebelow' => "\x{1E2B}",
- 'hcedilla' => "\x{1E29}",
- 'hcircle' => "\x{24D7}",
- 'hdieresis' => "\x{1E27}",
- 'hdotaccent' => "\x{1E23}",
- 'hdotbelow' => "\x{1E25}",
- 'he' => "\x{05D4}",
- 'heartsuitblack' => "\x{2665}",
- 'heartsuitwhite' => "\x{2661}",
- 'hedagesh' => "\x{FB34}",
- 'hedageshhebrew' => "\x{FB34}",
- 'hehaltonearabic' => "\x{06C1}",
- 'heharabic' => "\x{0647}",
- 'hehebrew' => "\x{05D4}",
- 'hehfinalaltonearabic' => "\x{FBA7}",
- 'hehfinalalttwoarabic' => "\x{FEEA}",
- 'hehfinalarabic' => "\x{FEEA}",
- 'hehhamzaabovefinalarabic' => "\x{FBA5}",
- 'hehhamzaaboveisolatedarabic' => "\x{FBA4}",
- 'hehinitialaltonearabic' => "\x{FBA8}",
- 'hehinitialarabic' => "\x{FEEB}",
- 'hehiragana' => "\x{3078}",
- 'hehmedialaltonearabic' => "\x{FBA9}",
- 'hehmedialarabic' => "\x{FEEC}",
- 'heiseierasquare' => "\x{337B}",
- 'hekatakana' => "\x{30D8}",
- 'hekatakanahalfwidth' => "\x{FF8D}",
- 'hekutaarusquare' => "\x{3336}",
- 'henghook' => "\x{0267}",
- 'herutusquare' => "\x{3339}",
- 'het' => "\x{05D7}",
- 'hethebrew' => "\x{05D7}",
- 'hhook' => "\x{0266}",
- 'hhooksuperior' => "\x{02B1}",
- 'hieuhacirclekorean' => "\x{327B}",
- 'hieuhaparenkorean' => "\x{321B}",
- 'hieuhcirclekorean' => "\x{326D}",
- 'hieuhkorean' => "\x{314E}",
- 'hieuhparenkorean' => "\x{320D}",
- 'hihiragana' => "\x{3072}",
- 'hikatakana' => "\x{30D2}",
- 'hikatakanahalfwidth' => "\x{FF8B}",
- 'hiriq' => "\x{05B4}",
- 'hiriq14' => "\x{05B4}",
- 'hiriq21' => "\x{05B4}",
- 'hiriq2d' => "\x{05B4}",
- 'hiriqhebrew' => "\x{05B4}",
- 'hiriqnarrowhebrew' => "\x{05B4}",
- 'hiriqquarterhebrew' => "\x{05B4}",
- 'hiriqwidehebrew' => "\x{05B4}",
- 'hlinebelow' => "\x{1E96}",
- 'hmonospace' => "\x{FF48}",
- 'hoarmenian' => "\x{0570}",
- 'hohipthai' => "\x{0E2B}",
- 'hohiragana' => "\x{307B}",
- 'hokatakana' => "\x{30DB}",
- 'hokatakanahalfwidth' => "\x{FF8E}",
- 'holam' => "\x{05B9}",
- 'holam19' => "\x{05B9}",
- 'holam26' => "\x{05B9}",
- 'holam32' => "\x{05B9}",
- 'holamhebrew' => "\x{05B9}",
- 'holamnarrowhebrew' => "\x{05B9}",
- 'holamquarterhebrew' => "\x{05B9}",
- 'holamwidehebrew' => "\x{05B9}",
- 'honokhukthai' => "\x{0E2E}",
- 'hookcmb' => "\x{0309}",
- 'hookpalatalizedbelowcmb' => "\x{0321}",
- 'hookretroflexbelowcmb' => "\x{0322}",
- 'hoonsquare' => "\x{3342}",
- 'horicoptic' => "\x{03E9}",
- 'horizontalbar' => "\x{2015}",
- 'horncmb' => "\x{031B}",
- 'hotsprings' => "\x{2668}",
- 'hparen' => "\x{24A3}",
- 'hsuperior' => "\x{02B0}",
- 'hturned' => "\x{0265}",
- 'huhiragana' => "\x{3075}",
- 'huiitosquare' => "\x{3333}",
- 'hukatakana' => "\x{30D5}",
- 'hukatakanahalfwidth' => "\x{FF8C}",
- 'hungarumlautcmb' => "\x{030B}",
- 'hv' => "\x{0195}",
- 'hypheninferior' => "\x{F6E5}",
- 'hyphenmonospace' => "\x{FF0D}",
- 'hyphensmall' => "\x{FE63}",
- 'hyphensuperior' => "\x{F6E6}",
- 'hyphentwo' => "\x{2010}",
- 'iacyrillic' => "\x{044F}",
- 'ibengali' => "\x{0987}",
- 'ibopomofo' => "\x{3127}",
- 'icaron' => "\x{01D0}",
- 'icircle' => "\x{24D8}",
- 'icyrillic' => "\x{0456}",
- 'idblgrave' => "\x{0209}",
- 'ideographearthcircle' => "\x{328F}",
- 'ideographfirecircle' => "\x{328B}",
- 'ideographicallianceparen' => "\x{323F}",
- 'ideographiccallparen' => "\x{323A}",
- 'ideographiccentrecircle' => "\x{32A5}",
- 'ideographicclose' => "\x{3006}",
- 'ideographiccomma' => "\x{3001}",
- 'ideographiccommaleft' => "\x{FF64}",
- 'ideographiccongratulationparen' => "\x{3237}",
- 'ideographiccorrectcircle' => "\x{32A3}",
- 'ideographicearthparen' => "\x{322F}",
- 'ideographicenterpriseparen' => "\x{323D}",
- 'ideographicexcellentcircle' => "\x{329D}",
- 'ideographicfestivalparen' => "\x{3240}",
- 'ideographicfinancialcircle' => "\x{3296}",
- 'ideographicfinancialparen' => "\x{3236}",
- 'ideographicfireparen' => "\x{322B}",
- 'ideographichaveparen' => "\x{3232}",
- 'ideographichighcircle' => "\x{32A4}",
- 'ideographiciterationmark' => "\x{3005}",
- 'ideographiclaborcircle' => "\x{3298}",
- 'ideographiclaborparen' => "\x{3238}",
- 'ideographicleftcircle' => "\x{32A7}",
- 'ideographiclowcircle' => "\x{32A6}",
- 'ideographicmedicinecircle' => "\x{32A9}",
- 'ideographicmetalparen' => "\x{322E}",
- 'ideographicmoonparen' => "\x{322A}",
- 'ideographicnameparen' => "\x{3234}",
- 'ideographicperiod' => "\x{3002}",
- 'ideographicprintcircle' => "\x{329E}",
- 'ideographicreachparen' => "\x{3243}",
- 'ideographicrepresentparen' => "\x{3239}",
- 'ideographicresourceparen' => "\x{323E}",
- 'ideographicrightcircle' => "\x{32A8}",
- 'ideographicsecretcircle' => "\x{3299}",
- 'ideographicselfparen' => "\x{3242}",
- 'ideographicsocietyparen' => "\x{3233}",
- 'ideographicspace' => "\x{3000}",
- 'ideographicspecialparen' => "\x{3235}",
- 'ideographicstockparen' => "\x{3231}",
- 'ideographicstudyparen' => "\x{323B}",
- 'ideographicsunparen' => "\x{3230}",
- 'ideographicsuperviseparen' => "\x{323C}",
- 'ideographicwaterparen' => "\x{322C}",
- 'ideographicwoodparen' => "\x{322D}",
- 'ideographiczero' => "\x{3007}",
- 'ideographmetalcircle' => "\x{328E}",
- 'ideographmooncircle' => "\x{328A}",
- 'ideographnamecircle' => "\x{3294}",
- 'ideographsuncircle' => "\x{3290}",
- 'ideographwatercircle' => "\x{328C}",
- 'ideographwoodcircle' => "\x{328D}",
- 'ideva' => "\x{0907}",
- 'idieresisacute' => "\x{1E2F}",
- 'idieresiscyrillic' => "\x{04E5}",
- 'idotbelow' => "\x{1ECB}",
- 'iebrevecyrillic' => "\x{04D7}",
- 'iecyrillic' => "\x{0435}",
- 'ieungacirclekorean' => "\x{3275}",
- 'ieungaparenkorean' => "\x{3215}",
- 'ieungcirclekorean' => "\x{3267}",
- 'ieungkorean' => "\x{3147}",
- 'ieungparenkorean' => "\x{3207}",
- 'igujarati' => "\x{0A87}",
- 'igurmukhi' => "\x{0A07}",
- 'ihiragana' => "\x{3044}",
- 'ihookabove' => "\x{1EC9}",
- 'iibengali' => "\x{0988}",
- 'iicyrillic' => "\x{0438}",
- 'iideva' => "\x{0908}",
- 'iigujarati' => "\x{0A88}",
- 'iigurmukhi' => "\x{0A08}",
- 'iimatragurmukhi' => "\x{0A40}",
- 'iinvertedbreve' => "\x{020B}",
- 'iishortcyrillic' => "\x{0439}",
- 'iivowelsignbengali' => "\x{09C0}",
- 'iivowelsigndeva' => "\x{0940}",
- 'iivowelsigngujarati' => "\x{0AC0}",
- 'ikatakana' => "\x{30A4}",
- 'ikatakanahalfwidth' => "\x{FF72}",
- 'ikorean' => "\x{3163}",
- 'ilde' => "\x{02DC}",
- 'iluyhebrew' => "\x{05AC}",
- 'imacroncyrillic' => "\x{04E3}",
- 'imageorapproximatelyequal' => "\x{2253}",
- 'imatragurmukhi' => "\x{0A3F}",
- 'imonospace' => "\x{FF49}",
- 'increment' => "\x{2206}",
- 'iniarmenian' => "\x{056B}",
- 'integralbottom' => "\x{2321}",
- 'integralex' => "\x{F8F5}",
- 'integraltop' => "\x{2320}",
- 'intisquare' => "\x{3305}",
- 'iocyrillic' => "\x{0451}",
- 'iotalatin' => "\x{0269}",
- 'iparen' => "\x{24A4}",
- 'irigurmukhi' => "\x{0A72}",
- 'ismallhiragana' => "\x{3043}",
- 'ismallkatakana' => "\x{30A3}",
- 'ismallkatakanahalfwidth' => "\x{FF68}",
- 'issharbengali' => "\x{09FA}",
- 'istroke' => "\x{0268}",
- 'isuperior' => "\x{F6ED}",
- 'iterationhiragana' => "\x{309D}",
- 'iterationkatakana' => "\x{30FD}",
- 'itildebelow' => "\x{1E2D}",
- 'iubopomofo' => "\x{3129}",
- 'iucyrillic' => "\x{044E}",
- 'ivowelsignbengali' => "\x{09BF}",
- 'ivowelsigndeva' => "\x{093F}",
- 'ivowelsigngujarati' => "\x{0ABF}",
- 'izhitsacyrillic' => "\x{0475}",
- 'izhitsadblgravecyrillic' => "\x{0477}",
- 'jaarmenian' => "\x{0571}",
- 'jabengali' => "\x{099C}",
- 'jadeva' => "\x{091C}",
- 'jagujarati' => "\x{0A9C}",
- 'jagurmukhi' => "\x{0A1C}",
- 'jbopomofo' => "\x{3110}",
- 'jcaron' => "\x{01F0}",
- 'jcircle' => "\x{24D9}",
- 'jcrossedtail' => "\x{029D}",
- 'jdotlessstroke' => "\x{025F}",
- 'jecyrillic' => "\x{0458}",
- 'jeemarabic' => "\x{062C}",
- 'jeemfinalarabic' => "\x{FE9E}",
- 'jeeminitialarabic' => "\x{FE9F}",
- 'jeemmedialarabic' => "\x{FEA0}",
- 'jeharabic' => "\x{0698}",
- 'jehfinalarabic' => "\x{FB8B}",
- 'jhabengali' => "\x{099D}",
- 'jhadeva' => "\x{091D}",
- 'jhagujarati' => "\x{0A9D}",
- 'jhagurmukhi' => "\x{0A1D}",
- 'jheharmenian' => "\x{057B}",
- 'jis' => "\x{3004}",
- 'jmonospace' => "\x{FF4A}",
- 'jparen' => "\x{24A5}",
- 'jsuperior' => "\x{02B2}",
- 'kabashkircyrillic' => "\x{04A1}",
- 'kabengali' => "\x{0995}",
- 'kacute' => "\x{1E31}",
- 'kacyrillic' => "\x{043A}",
- 'kadescendercyrillic' => "\x{049B}",
- 'kadeva' => "\x{0915}",
- 'kaf' => "\x{05DB}",
- 'kafarabic' => "\x{0643}",
- 'kafdagesh' => "\x{FB3B}",
- 'kafdageshhebrew' => "\x{FB3B}",
- 'kaffinalarabic' => "\x{FEDA}",
- 'kafhebrew' => "\x{05DB}",
- 'kafinitialarabic' => "\x{FEDB}",
- 'kafmedialarabic' => "\x{FEDC}",
- 'kafrafehebrew' => "\x{FB4D}",
- 'kagujarati' => "\x{0A95}",
- 'kagurmukhi' => "\x{0A15}",
- 'kahiragana' => "\x{304B}",
- 'kahookcyrillic' => "\x{04C4}",
- 'kakatakana' => "\x{30AB}",
- 'kakatakanahalfwidth' => "\x{FF76}",
- 'kappasymbolgreek' => "\x{03F0}",
- 'kapyeounmieumkorean' => "\x{3171}",
- 'kapyeounphieuphkorean' => "\x{3184}",
- 'kapyeounpieupkorean' => "\x{3178}",
- 'kapyeounssangpieupkorean' => "\x{3179}",
- 'karoriisquare' => "\x{330D}",
- 'kashidaautoarabic' => "\x{0640}",
- 'kashidaautonosidebearingarabic' => "\x{0640}",
- 'kasmallkatakana' => "\x{30F5}",
- 'kasquare' => "\x{3384}",
- 'kasraarabic' => "\x{0650}",
- 'kasratanarabic' => "\x{064D}",
- 'kastrokecyrillic' => "\x{049F}",
- 'katahiraprolongmarkhalfwidth' => "\x{FF70}",
- 'kaverticalstrokecyrillic' => "\x{049D}",
- 'kbopomofo' => "\x{310E}",
- 'kcalsquare' => "\x{3389}",
- 'kcaron' => "\x{01E9}",
- 'kcedilla' => "\x{0137}",
- 'kcircle' => "\x{24DA}",
- 'kdotbelow' => "\x{1E33}",
- 'keharmenian' => "\x{0584}",
- 'kehiragana' => "\x{3051}",
- 'kekatakana' => "\x{30B1}",
- 'kekatakanahalfwidth' => "\x{FF79}",
- 'kenarmenian' => "\x{056F}",
- 'kesmallkatakana' => "\x{30F6}",
- 'khabengali' => "\x{0996}",
- 'khacyrillic' => "\x{0445}",
- 'khadeva' => "\x{0916}",
- 'khagujarati' => "\x{0A96}",
- 'khagurmukhi' => "\x{0A16}",
- 'khaharabic' => "\x{062E}",
- 'khahfinalarabic' => "\x{FEA6}",
- 'khahinitialarabic' => "\x{FEA7}",
- 'khahmedialarabic' => "\x{FEA8}",
- 'kheicoptic' => "\x{03E7}",
- 'khhadeva' => "\x{0959}",
- 'khhagurmukhi' => "\x{0A59}",
- 'khieukhacirclekorean' => "\x{3278}",
- 'khieukhaparenkorean' => "\x{3218}",
- 'khieukhcirclekorean' => "\x{326A}",
- 'khieukhkorean' => "\x{314B}",
- 'khieukhparenkorean' => "\x{320A}",
- 'khokhaithai' => "\x{0E02}",
- 'khokhonthai' => "\x{0E05}",
- 'khokhuatthai' => "\x{0E03}",
- 'khokhwaithai' => "\x{0E04}",
- 'khomutthai' => "\x{0E5B}",
- 'khook' => "\x{0199}",
- 'khorakhangthai' => "\x{0E06}",
- 'khzsquare' => "\x{3391}",
- 'kihiragana' => "\x{304D}",
- 'kikatakana' => "\x{30AD}",
- 'kikatakanahalfwidth' => "\x{FF77}",
- 'kiroguramusquare' => "\x{3315}",
- 'kiromeetorusquare' => "\x{3316}",
- 'kirosquare' => "\x{3314}",
- 'kiyeokacirclekorean' => "\x{326E}",
- 'kiyeokaparenkorean' => "\x{320E}",
- 'kiyeokcirclekorean' => "\x{3260}",
- 'kiyeokkorean' => "\x{3131}",
- 'kiyeokparenkorean' => "\x{3200}",
- 'kiyeoksioskorean' => "\x{3133}",
- 'kjecyrillic' => "\x{045C}",
- 'klinebelow' => "\x{1E35}",
- 'klsquare' => "\x{3398}",
- 'kmcubedsquare' => "\x{33A6}",
- 'kmonospace' => "\x{FF4B}",
- 'kmsquaredsquare' => "\x{33A2}",
- 'kohiragana' => "\x{3053}",
- 'kohmsquare' => "\x{33C0}",
- 'kokaithai' => "\x{0E01}",
- 'kokatakana' => "\x{30B3}",
- 'kokatakanahalfwidth' => "\x{FF7A}",
- 'kooposquare' => "\x{331E}",
- 'koppacyrillic' => "\x{0481}",
- 'koreanstandardsymbol' => "\x{327F}",
- 'koroniscmb' => "\x{0343}",
- 'kparen' => "\x{24A6}",
- 'kpasquare' => "\x{33AA}",
- 'ksicyrillic' => "\x{046F}",
- 'ktsquare' => "\x{33CF}",
- 'kturned' => "\x{029E}",
- 'kuhiragana' => "\x{304F}",
- 'kukatakana' => "\x{30AF}",
- 'kukatakanahalfwidth' => "\x{FF78}",
- 'kvsquare' => "\x{33B8}",
- 'kwsquare' => "\x{33BE}",
- 'labengali' => "\x{09B2}",
- 'ladeva' => "\x{0932}",
- 'lagujarati' => "\x{0AB2}",
- 'lagurmukhi' => "\x{0A32}",
- 'lakkhangyaothai' => "\x{0E45}",
- 'lamaleffinalarabic' => "\x{FEFC}",
- 'lamalefhamzaabovefinalarabic' => "\x{FEF8}",
- 'lamalefhamzaaboveisolatedarabic' => "\x{FEF7}",
- 'lamalefhamzabelowfinalarabic' => "\x{FEFA}",
- 'lamalefhamzabelowisolatedarabic' => "\x{FEF9}",
- 'lamalefisolatedarabic' => "\x{FEFB}",
- 'lamalefmaddaabovefinalarabic' => "\x{FEF6}",
- 'lamalefmaddaaboveisolatedarabic' => "\x{FEF5}",
- 'lamarabic' => "\x{0644}",
- 'lambdastroke' => "\x{019B}",
- 'lamed' => "\x{05DC}",
- 'lameddagesh' => "\x{FB3C}",
- 'lameddageshhebrew' => "\x{FB3C}",
- 'lamedhebrew' => "\x{05DC}",
- 'lamedholam' => "\x{05DC}\x{05B9}",
- 'lamedholamdagesh' => "\x{05DC}\x{05B9}\x{05BC}",
- 'lamedholamdageshhebrew' => "\x{05DC}\x{05B9}\x{05BC}",
- 'lamedholamhebrew' => "\x{05DC}\x{05B9}",
- 'lamfinalarabic' => "\x{FEDE}",
- 'lamhahinitialarabic' => "\x{FCCA}",
- 'laminitialarabic' => "\x{FEDF}",
- 'lamjeeminitialarabic' => "\x{FCC9}",
- 'lamkhahinitialarabic' => "\x{FCCB}",
- 'lamlamhehisolatedarabic' => "\x{FDF2}",
- 'lammedialarabic' => "\x{FEE0}",
- 'lammeemhahinitialarabic' => "\x{FD88}",
- 'lammeeminitialarabic' => "\x{FCCC}",
- 'lammeemjeeminitialarabic' => "\x{FEDF}\x{FEE4}\x{FEA0}",
- 'lammeemkhahinitialarabic' => "\x{FEDF}\x{FEE4}\x{FEA8}",
- 'largecircle' => "\x{25EF}",
- 'lbar' => "\x{019A}",
- 'lbelt' => "\x{026C}",
- 'lbopomofo' => "\x{310C}",
- 'lcedilla' => "\x{013C}",
- 'lcircle' => "\x{24DB}",
- 'lcircumflexbelow' => "\x{1E3D}",
- 'ldotaccent' => "\x{0140}",
- 'ldotbelow' => "\x{1E37}",
- 'ldotbelowmacron' => "\x{1E39}",
- 'leftangleabovecmb' => "\x{031A}",
- 'lefttackbelowcmb' => "\x{0318}",
- 'lessequalorgreater' => "\x{22DA}",
- 'lessmonospace' => "\x{FF1C}",
- 'lessorequivalent' => "\x{2272}",
- 'lessorgreater' => "\x{2276}",
- 'lessoverequal' => "\x{2266}",
- 'lesssmall' => "\x{FE64}",
- 'lezh' => "\x{026E}",
- 'lhookretroflex' => "\x{026D}",
- 'liwnarmenian' => "\x{056C}",
- 'lj' => "\x{01C9}",
- 'ljecyrillic' => "\x{0459}",
- 'll' => "\x{F6C0}",
- 'lladeva' => "\x{0933}",
- 'llagujarati' => "\x{0AB3}",
- 'llinebelow' => "\x{1E3B}",
- 'llladeva' => "\x{0934}",
- 'llvocalicbengali' => "\x{09E1}",
- 'llvocalicdeva' => "\x{0961}",
- 'llvocalicvowelsignbengali' => "\x{09E3}",
- 'llvocalicvowelsigndeva' => "\x{0963}",
- 'lmiddletilde' => "\x{026B}",
- 'lmonospace' => "\x{FF4C}",
- 'lmsquare' => "\x{33D0}",
- 'lochulathai' => "\x{0E2C}",
- 'logicalnotreversed' => "\x{2310}",
- 'lolingthai' => "\x{0E25}",
- 'lowlinecenterline' => "\x{FE4E}",
- 'lowlinecmb' => "\x{0332}",
- 'lowlinedashed' => "\x{FE4D}",
- 'lparen' => "\x{24A7}",
- 'lsquare' => "\x{2113}",
- 'lsuperior' => "\x{F6EE}",
- 'luthai' => "\x{0E26}",
- 'lvocalicbengali' => "\x{098C}",
- 'lvocalicdeva' => "\x{090C}",
- 'lvocalicvowelsignbengali' => "\x{09E2}",
- 'lvocalicvowelsigndeva' => "\x{0962}",
- 'lxsquare' => "\x{33D3}",
- 'mabengali' => "\x{09AE}",
- 'macronbelowcmb' => "\x{0331}",
- 'macroncmb' => "\x{0304}",
- 'macronlowmod' => "\x{02CD}",
- 'macronmonospace' => "\x{FFE3}",
- 'macute' => "\x{1E3F}",
- 'madeva' => "\x{092E}",
- 'magujarati' => "\x{0AAE}",
- 'magurmukhi' => "\x{0A2E}",
- 'mahapakhhebrew' => "\x{05A4}",
- 'mahapakhlefthebrew' => "\x{05A4}",
- 'mahiragana' => "\x{307E}",
- 'maichattawalowleftthai' => "\x{F895}",
- 'maichattawalowrightthai' => "\x{F894}",
- 'maichattawathai' => "\x{0E4B}",
- 'maichattawaupperleftthai' => "\x{F893}",
- 'maieklowleftthai' => "\x{F88C}",
- 'maieklowrightthai' => "\x{F88B}",
- 'maiekthai' => "\x{0E48}",
- 'maiekupperleftthai' => "\x{F88A}",
- 'maihanakatleftthai' => "\x{F884}",
- 'maihanakatthai' => "\x{0E31}",
- 'maitaikhuleftthai' => "\x{F889}",
- 'maitaikhuthai' => "\x{0E47}",
- 'maitholowleftthai' => "\x{F88F}",
- 'maitholowrightthai' => "\x{F88E}",
- 'maithothai' => "\x{0E49}",
- 'maithoupperleftthai' => "\x{F88D}",
- 'maitrilowleftthai' => "\x{F892}",
- 'maitrilowrightthai' => "\x{F891}",
- 'maitrithai' => "\x{0E4A}",
- 'maitriupperleftthai' => "\x{F890}",
- 'maiyamokthai' => "\x{0E46}",
- 'makatakana' => "\x{30DE}",
- 'makatakanahalfwidth' => "\x{FF8F}",
- 'mansyonsquare' => "\x{3347}",
- 'maqafhebrew' => "\x{05BE}",
- 'mars' => "\x{2642}",
- 'masoracirclehebrew' => "\x{05AF}",
- 'masquare' => "\x{3383}",
- 'mbopomofo' => "\x{3107}",
- 'mbsquare' => "\x{33D4}",
- 'mcircle' => "\x{24DC}",
- 'mcubedsquare' => "\x{33A5}",
- 'mdotaccent' => "\x{1E41}",
- 'mdotbelow' => "\x{1E43}",
- 'meemarabic' => "\x{0645}",
- 'meemfinalarabic' => "\x{FEE2}",
- 'meeminitialarabic' => "\x{FEE3}",
- 'meemmedialarabic' => "\x{FEE4}",
- 'meemmeeminitialarabic' => "\x{FCD1}",
- 'meemmeemisolatedarabic' => "\x{FC48}",
- 'meetorusquare' => "\x{334D}",
- 'mehiragana' => "\x{3081}",
- 'meizierasquare' => "\x{337E}",
- 'mekatakana' => "\x{30E1}",
- 'mekatakanahalfwidth' => "\x{FF92}",
- 'mem' => "\x{05DE}",
- 'memdagesh' => "\x{FB3E}",
- 'memdageshhebrew' => "\x{FB3E}",
- 'memhebrew' => "\x{05DE}",
- 'menarmenian' => "\x{0574}",
- 'merkhahebrew' => "\x{05A5}",
- 'merkhakefulahebrew' => "\x{05A6}",
- 'merkhakefulalefthebrew' => "\x{05A6}",
- 'merkhalefthebrew' => "\x{05A5}",
- 'mhook' => "\x{0271}",
- 'mhzsquare' => "\x{3392}",
- 'middledotkatakanahalfwidth' => "\x{FF65}",
- 'middot' => "\x{00B7}",
- 'mieumacirclekorean' => "\x{3272}",
- 'mieumaparenkorean' => "\x{3212}",
- 'mieumcirclekorean' => "\x{3264}",
- 'mieumkorean' => "\x{3141}",
- 'mieumpansioskorean' => "\x{3170}",
- 'mieumparenkorean' => "\x{3204}",
- 'mieumpieupkorean' => "\x{316E}",
- 'mieumsioskorean' => "\x{316F}",
- 'mihiragana' => "\x{307F}",
- 'mikatakana' => "\x{30DF}",
- 'mikatakanahalfwidth' => "\x{FF90}",
- 'minusbelowcmb' => "\x{0320}",
- 'minuscircle' => "\x{2296}",
- 'minusmod' => "\x{02D7}",
- 'minusplus' => "\x{2213}",
- 'miribaarusquare' => "\x{334A}",
- 'mirisquare' => "\x{3349}",
- 'mlonglegturned' => "\x{0270}",
- 'mlsquare' => "\x{3396}",
- 'mmcubedsquare' => "\x{33A3}",
- 'mmonospace' => "\x{FF4D}",
- 'mmsquaredsquare' => "\x{339F}",
- 'mohiragana' => "\x{3082}",
- 'mohmsquare' => "\x{33C1}",
- 'mokatakana' => "\x{30E2}",
- 'mokatakanahalfwidth' => "\x{FF93}",
- 'molsquare' => "\x{33D6}",
- 'momathai' => "\x{0E21}",
- 'moverssquare' => "\x{33A7}",
- 'moverssquaredsquare' => "\x{33A8}",
- 'mparen' => "\x{24A8}",
- 'mpasquare' => "\x{33AB}",
- 'mssquare' => "\x{33B3}",
- 'msuperior' => "\x{F6EF}",
- 'mturned' => "\x{026F}",
- 'mu1' => "\x{00B5}",
- 'muasquare' => "\x{3382}",
- 'muchgreater' => "\x{226B}",
- 'muchless' => "\x{226A}",
- 'mufsquare' => "\x{338C}",
- 'mugreek' => "\x{03BC}",
- 'mugsquare' => "\x{338D}",
- 'muhiragana' => "\x{3080}",
- 'mukatakana' => "\x{30E0}",
- 'mukatakanahalfwidth' => "\x{FF91}",
- 'mulsquare' => "\x{3395}",
- 'mumsquare' => "\x{339B}",
- 'munahhebrew' => "\x{05A3}",
- 'munahlefthebrew' => "\x{05A3}",
- 'musicflatsign' => "\x{266D}",
- 'musicsharpsign' => "\x{266F}",
- 'mussquare' => "\x{33B2}",
- 'muvsquare' => "\x{33B6}",
- 'muwsquare' => "\x{33BC}",
- 'mvmegasquare' => "\x{33B9}",
- 'mvsquare' => "\x{33B7}",
- 'mwmegasquare' => "\x{33BF}",
- 'mwsquare' => "\x{33BD}",
- 'nabengali' => "\x{09A8}",
- 'nabla' => "\x{2207}",
- 'nadeva' => "\x{0928}",
- 'nagujarati' => "\x{0AA8}",
- 'nagurmukhi' => "\x{0A28}",
- 'nahiragana' => "\x{306A}",
- 'nakatakana' => "\x{30CA}",
- 'nakatakanahalfwidth' => "\x{FF85}",
- 'nasquare' => "\x{3381}",
- 'nbopomofo' => "\x{310B}",
- 'nbspace' => "\x{00A0}",
- 'ncedilla' => "\x{0146}",
- 'ncircle' => "\x{24DD}",
- 'ncircumflexbelow' => "\x{1E4B}",
- 'ndotaccent' => "\x{1E45}",
- 'ndotbelow' => "\x{1E47}",
- 'nehiragana' => "\x{306D}",
- 'nekatakana' => "\x{30CD}",
- 'nekatakanahalfwidth' => "\x{FF88}",
- 'newsheqelsign' => "\x{20AA}",
- 'nfsquare' => "\x{338B}",
- 'ngabengali' => "\x{0999}",
- 'ngadeva' => "\x{0919}",
- 'ngagujarati' => "\x{0A99}",
- 'ngagurmukhi' => "\x{0A19}",
- 'ngonguthai' => "\x{0E07}",
- 'nhiragana' => "\x{3093}",
- 'nhookleft' => "\x{0272}",
- 'nhookretroflex' => "\x{0273}",
- 'nieunacirclekorean' => "\x{326F}",
- 'nieunaparenkorean' => "\x{320F}",
- 'nieuncieuckorean' => "\x{3135}",
- 'nieuncirclekorean' => "\x{3261}",
- 'nieunhieuhkorean' => "\x{3136}",
- 'nieunkorean' => "\x{3134}",
- 'nieunpansioskorean' => "\x{3168}",
- 'nieunparenkorean' => "\x{3201}",
- 'nieunsioskorean' => "\x{3167}",
- 'nieuntikeutkorean' => "\x{3166}",
- 'nihiragana' => "\x{306B}",
- 'nikatakana' => "\x{30CB}",
- 'nikatakanahalfwidth' => "\x{FF86}",
- 'nikhahitleftthai' => "\x{F899}",
- 'nikhahitthai' => "\x{0E4D}",
- 'ninearabic' => "\x{0669}",
- 'ninebengali' => "\x{09EF}",
- 'ninecircle' => "\x{2468}",
- 'ninecircleinversesansserif' => "\x{2792}",
- 'ninedeva' => "\x{096F}",
- 'ninegujarati' => "\x{0AEF}",
- 'ninegurmukhi' => "\x{0A6F}",
- 'ninehackarabic' => "\x{0669}",
- 'ninehangzhou' => "\x{3029}",
- 'nineideographicparen' => "\x{3228}",
- 'nineinferior' => "\x{2089}",
- 'ninemonospace' => "\x{FF19}",
- 'nineoldstyle' => "\x{F739}",
- 'nineparen' => "\x{247C}",
- 'nineperiod' => "\x{2490}",
- 'ninepersian' => "\x{06F9}",
- 'nineroman' => "\x{2178}",
- 'ninesuperior' => "\x{2079}",
- 'nineteencircle' => "\x{2472}",
- 'nineteenparen' => "\x{2486}",
- 'nineteenperiod' => "\x{249A}",
- 'ninethai' => "\x{0E59}",
- 'nj' => "\x{01CC}",
- 'njecyrillic' => "\x{045A}",
- 'nkatakana' => "\x{30F3}",
- 'nkatakanahalfwidth' => "\x{FF9D}",
- 'nlegrightlong' => "\x{019E}",
- 'nlinebelow' => "\x{1E49}",
- 'nmonospace' => "\x{FF4E}",
- 'nmsquare' => "\x{339A}",
- 'nnabengali' => "\x{09A3}",
- 'nnadeva' => "\x{0923}",
- 'nnagujarati' => "\x{0AA3}",
- 'nnagurmukhi' => "\x{0A23}",
- 'nnnadeva' => "\x{0929}",
- 'nohiragana' => "\x{306E}",
- 'nokatakana' => "\x{30CE}",
- 'nokatakanahalfwidth' => "\x{FF89}",
- 'nonbreakingspace' => "\x{00A0}",
- 'nonenthai' => "\x{0E13}",
- 'nonuthai' => "\x{0E19}",
- 'noonarabic' => "\x{0646}",
- 'noonfinalarabic' => "\x{FEE6}",
- 'noonghunnaarabic' => "\x{06BA}",
- 'noonghunnafinalarabic' => "\x{FB9F}",
- 'noonhehinitialarabic' => "\x{FEE7}\x{FEEC}",
- 'nooninitialarabic' => "\x{FEE7}",
- 'noonjeeminitialarabic' => "\x{FCD2}",
- 'noonjeemisolatedarabic' => "\x{FC4B}",
- 'noonmedialarabic' => "\x{FEE8}",
- 'noonmeeminitialarabic' => "\x{FCD5}",
- 'noonmeemisolatedarabic' => "\x{FC4E}",
- 'noonnoonfinalarabic' => "\x{FC8D}",
- 'notcontains' => "\x{220C}",
- 'notelementof' => "\x{2209}",
- 'notgreater' => "\x{226F}",
- 'notgreaternorequal' => "\x{2271}",
- 'notgreaternorless' => "\x{2279}",
- 'notidentical' => "\x{2262}",
- 'notless' => "\x{226E}",
- 'notlessnorequal' => "\x{2270}",
- 'notparallel' => "\x{2226}",
- 'notprecedes' => "\x{2280}",
- 'notsucceeds' => "\x{2281}",
- 'notsuperset' => "\x{2285}",
- 'nowarmenian' => "\x{0576}",
- 'nparen' => "\x{24A9}",
- 'nssquare' => "\x{33B1}",
- 'nsuperior' => "\x{207F}",
- 'nuhiragana' => "\x{306C}",
- 'nukatakana' => "\x{30CC}",
- 'nukatakanahalfwidth' => "\x{FF87}",
- 'nuktabengali' => "\x{09BC}",
- 'nuktadeva' => "\x{093C}",
- 'nuktagujarati' => "\x{0ABC}",
- 'nuktagurmukhi' => "\x{0A3C}",
- 'numbersignmonospace' => "\x{FF03}",
- 'numbersignsmall' => "\x{FE5F}",
- 'numeralsigngreek' => "\x{0374}",
- 'numeralsignlowergreek' => "\x{0375}",
- 'numero' => "\x{2116}",
- 'nun' => "\x{05E0}",
- 'nundagesh' => "\x{FB40}",
- 'nundageshhebrew' => "\x{FB40}",
- 'nunhebrew' => "\x{05E0}",
- 'nvsquare' => "\x{33B5}",
- 'nwsquare' => "\x{33BB}",
- 'nyabengali' => "\x{099E}",
- 'nyadeva' => "\x{091E}",
- 'nyagujarati' => "\x{0A9E}",
- 'nyagurmukhi' => "\x{0A1E}",
- 'oangthai' => "\x{0E2D}",
- 'obarred' => "\x{0275}",
- 'obarredcyrillic' => "\x{04E9}",
- 'obarreddieresiscyrillic' => "\x{04EB}",
- 'obengali' => "\x{0993}",
- 'obopomofo' => "\x{311B}",
- 'ocandradeva' => "\x{0911}",
- 'ocandragujarati' => "\x{0A91}",
- 'ocandravowelsigndeva' => "\x{0949}",
- 'ocandravowelsigngujarati' => "\x{0AC9}",
- 'ocaron' => "\x{01D2}",
- 'ocircle' => "\x{24DE}",
- 'ocircumflexacute' => "\x{1ED1}",
- 'ocircumflexdotbelow' => "\x{1ED9}",
- 'ocircumflexgrave' => "\x{1ED3}",
- 'ocircumflexhookabove' => "\x{1ED5}",
- 'ocircumflextilde' => "\x{1ED7}",
- 'ocyrillic' => "\x{043E}",
- 'odblacute' => "\x{0151}",
- 'odblgrave' => "\x{020D}",
- 'odeva' => "\x{0913}",
- 'odieresiscyrillic' => "\x{04E7}",
- 'odotbelow' => "\x{1ECD}",
- 'oekorean' => "\x{315A}",
- 'ogonekcmb' => "\x{0328}",
- 'ogujarati' => "\x{0A93}",
- 'oharmenian' => "\x{0585}",
- 'ohiragana' => "\x{304A}",
- 'ohookabove' => "\x{1ECF}",
- 'ohornacute' => "\x{1EDB}",
- 'ohorndotbelow' => "\x{1EE3}",
- 'ohorngrave' => "\x{1EDD}",
- 'ohornhookabove' => "\x{1EDF}",
- 'ohorntilde' => "\x{1EE1}",
- 'oi' => "\x{01A3}",
- 'oinvertedbreve' => "\x{020F}",
- 'okatakana' => "\x{30AA}",
- 'okatakanahalfwidth' => "\x{FF75}",
- 'okorean' => "\x{3157}",
- 'olehebrew' => "\x{05AB}",
- 'omacronacute' => "\x{1E53}",
- 'omacrongrave' => "\x{1E51}",
- 'omdeva' => "\x{0950}",
- 'omegacyrillic' => "\x{0461}",
- 'omegalatinclosed' => "\x{0277}",
- 'omegaroundcyrillic' => "\x{047B}",
- 'omegatitlocyrillic' => "\x{047D}",
- 'omgujarati' => "\x{0AD0}",
- 'omonospace' => "\x{FF4F}",
- 'onearabic' => "\x{0661}",
- 'onebengali' => "\x{09E7}",
- 'onecircle' => "\x{2460}",
- 'onecircleinversesansserif' => "\x{278A}",
- 'onedeva' => "\x{0967}",
- 'onefitted' => "\x{F6DC}",
- 'onegujarati' => "\x{0AE7}",
- 'onegurmukhi' => "\x{0A67}",
- 'onehackarabic' => "\x{0661}",
- 'onehangzhou' => "\x{3021}",
- 'oneideographicparen' => "\x{3220}",
- 'oneinferior' => "\x{2081}",
- 'onemonospace' => "\x{FF11}",
- 'onenumeratorbengali' => "\x{09F4}",
- 'oneoldstyle' => "\x{F731}",
- 'oneparen' => "\x{2474}",
- 'oneperiod' => "\x{2488}",
- 'onepersian' => "\x{06F1}",
- 'oneroman' => "\x{2170}",
- 'onethai' => "\x{0E51}",
- 'oogonek' => "\x{01EB}",
- 'oogonekmacron' => "\x{01ED}",
- 'oogurmukhi' => "\x{0A13}",
- 'oomatragurmukhi' => "\x{0A4B}",
- 'oopen' => "\x{0254}",
- 'oparen' => "\x{24AA}",
- 'option' => "\x{2325}",
- 'oshortdeva' => "\x{0912}",
- 'oshortvowelsigndeva' => "\x{094A}",
- 'osmallhiragana' => "\x{3049}",
- 'osmallkatakana' => "\x{30A9}",
- 'osmallkatakanahalfwidth' => "\x{FF6B}",
- 'ostrokeacute' => "\x{01FF}",
- 'osuperior' => "\x{F6F0}",
- 'otcyrillic' => "\x{047F}",
- 'otildeacute' => "\x{1E4D}",
- 'otildedieresis' => "\x{1E4F}",
- 'oubopomofo' => "\x{3121}",
- 'overline' => "\x{203E}",
- 'overlinecenterline' => "\x{FE4A}",
- 'overlinecmb' => "\x{0305}",
- 'overlinedashed' => "\x{FE49}",
- 'overlinedblwavy' => "\x{FE4C}",
- 'overlinewavy' => "\x{FE4B}",
- 'overscore' => "\x{00AF}",
- 'ovowelsignbengali' => "\x{09CB}",
- 'ovowelsigndeva' => "\x{094B}",
- 'ovowelsigngujarati' => "\x{0ACB}",
- 'paampssquare' => "\x{3380}",
- 'paasentosquare' => "\x{332B}",
- 'pabengali' => "\x{09AA}",
- 'pacute' => "\x{1E55}",
- 'padeva' => "\x{092A}",
- 'pagedown' => "\x{21DF}",
- 'pageup' => "\x{21DE}",
- 'pagujarati' => "\x{0AAA}",
- 'pagurmukhi' => "\x{0A2A}",
- 'pahiragana' => "\x{3071}",
- 'paiyannoithai' => "\x{0E2F}",
- 'pakatakana' => "\x{30D1}",
- 'palatalizationcyrilliccmb' => "\x{0484}",
- 'palochkacyrillic' => "\x{04C0}",
- 'pansioskorean' => "\x{317F}",
- 'parallel' => "\x{2225}",
- 'parenleftaltonearabic' => "\x{FD3E}",
- 'parenleftbt' => "\x{F8ED}",
- 'parenleftex' => "\x{F8EC}",
- 'parenleftinferior' => "\x{208D}",
- 'parenleftmonospace' => "\x{FF08}",
- 'parenleftsmall' => "\x{FE59}",
- 'parenleftsuperior' => "\x{207D}",
- 'parenlefttp' => "\x{F8EB}",
- 'parenleftvertical' => "\x{FE35}",
- 'parenrightaltonearabic' => "\x{FD3F}",
- 'parenrightbt' => "\x{F8F8}",
- 'parenrightex' => "\x{F8F7}",
- 'parenrightinferior' => "\x{208E}",
- 'parenrightmonospace' => "\x{FF09}",
- 'parenrightsmall' => "\x{FE5A}",
- 'parenrightsuperior' => "\x{207E}",
- 'parenrighttp' => "\x{F8F6}",
- 'parenrightvertical' => "\x{FE36}",
- 'paseqhebrew' => "\x{05C0}",
- 'pashtahebrew' => "\x{0599}",
- 'pasquare' => "\x{33A9}",
- 'patah' => "\x{05B7}",
- 'patah11' => "\x{05B7}",
- 'patah1d' => "\x{05B7}",
- 'patah2a' => "\x{05B7}",
- 'patahhebrew' => "\x{05B7}",
- 'patahnarrowhebrew' => "\x{05B7}",
- 'patahquarterhebrew' => "\x{05B7}",
- 'patahwidehebrew' => "\x{05B7}",
- 'pazerhebrew' => "\x{05A1}",
- 'pbopomofo' => "\x{3106}",
- 'pcircle' => "\x{24DF}",
- 'pdotaccent' => "\x{1E57}",
- 'pe' => "\x{05E4}",
- 'pecyrillic' => "\x{043F}",
- 'pedagesh' => "\x{FB44}",
- 'pedageshhebrew' => "\x{FB44}",
- 'peezisquare' => "\x{333B}",
- 'pefinaldageshhebrew' => "\x{FB43}",
- 'peharabic' => "\x{067E}",
- 'peharmenian' => "\x{057A}",
- 'pehebrew' => "\x{05E4}",
- 'pehfinalarabic' => "\x{FB57}",
- 'pehinitialarabic' => "\x{FB58}",
- 'pehiragana' => "\x{307A}",
- 'pehmedialarabic' => "\x{FB59}",
- 'pekatakana' => "\x{30DA}",
- 'pemiddlehookcyrillic' => "\x{04A7}",
- 'perafehebrew' => "\x{FB4E}",
- 'percentarabic' => "\x{066A}",
- 'percentmonospace' => "\x{FF05}",
- 'percentsmall' => "\x{FE6A}",
- 'periodarmenian' => "\x{0589}",
- 'periodhalfwidth' => "\x{FF61}",
- 'periodinferior' => "\x{F6E7}",
- 'periodmonospace' => "\x{FF0E}",
- 'periodsmall' => "\x{FE52}",
- 'periodsuperior' => "\x{F6E8}",
- 'perispomenigreekcmb' => "\x{0342}",
- 'pfsquare' => "\x{338A}",
- 'phabengali' => "\x{09AB}",
- 'phadeva' => "\x{092B}",
- 'phagujarati' => "\x{0AAB}",
- 'phagurmukhi' => "\x{0A2B}",
- 'phieuphacirclekorean' => "\x{327A}",
- 'phieuphaparenkorean' => "\x{321A}",
- 'phieuphcirclekorean' => "\x{326C}",
- 'phieuphkorean' => "\x{314D}",
- 'phieuphparenkorean' => "\x{320C}",
- 'philatin' => "\x{0278}",
- 'phinthuthai' => "\x{0E3A}",
- 'phisymbolgreek' => "\x{03D5}",
- 'phook' => "\x{01A5}",
- 'phophanthai' => "\x{0E1E}",
- 'phophungthai' => "\x{0E1C}",
- 'phosamphaothai' => "\x{0E20}",
- 'pieupacirclekorean' => "\x{3273}",
- 'pieupaparenkorean' => "\x{3213}",
- 'pieupcieuckorean' => "\x{3176}",
- 'pieupcirclekorean' => "\x{3265}",
- 'pieupkiyeokkorean' => "\x{3172}",
- 'pieupkorean' => "\x{3142}",
- 'pieupparenkorean' => "\x{3205}",
- 'pieupsioskiyeokkorean' => "\x{3174}",
- 'pieupsioskorean' => "\x{3144}",
- 'pieupsiostikeutkorean' => "\x{3175}",
- 'pieupthieuthkorean' => "\x{3177}",
- 'pieuptikeutkorean' => "\x{3173}",
- 'pihiragana' => "\x{3074}",
- 'pikatakana' => "\x{30D4}",
- 'pisymbolgreek' => "\x{03D6}",
- 'piwrarmenian' => "\x{0583}",
- 'plusbelowcmb' => "\x{031F}",
- 'pluscircle' => "\x{2295}",
- 'plusmod' => "\x{02D6}",
- 'plusmonospace' => "\x{FF0B}",
- 'plussmall' => "\x{FE62}",
- 'plussuperior' => "\x{207A}",
- 'pmonospace' => "\x{FF50}",
- 'pmsquare' => "\x{33D8}",
- 'pohiragana' => "\x{307D}",
- 'pointingindexdownwhite' => "\x{261F}",
- 'pointingindexleftwhite' => "\x{261C}",
- 'pointingindexrightwhite' => "\x{261E}",
- 'pointingindexupwhite' => "\x{261D}",
- 'pokatakana' => "\x{30DD}",
- 'poplathai' => "\x{0E1B}",
- 'postalmark' => "\x{3012}",
- 'postalmarkface' => "\x{3020}",
- 'pparen' => "\x{24AB}",
- 'precedes' => "\x{227A}",
- 'primemod' => "\x{02B9}",
- 'primereversed' => "\x{2035}",
- 'projective' => "\x{2305}",
- 'prolongedkana' => "\x{30FC}",
- 'propellor' => "\x{2318}",
- 'proportion' => "\x{2237}",
- 'psicyrillic' => "\x{0471}",
- 'psilipneumatacyrilliccmb' => "\x{0486}",
- 'pssquare' => "\x{33B0}",
- 'puhiragana' => "\x{3077}",
- 'pukatakana' => "\x{30D7}",
- 'pvsquare' => "\x{33B4}",
- 'pwsquare' => "\x{33BA}",
- 'qadeva' => "\x{0958}",
- 'qadmahebrew' => "\x{05A8}",
- 'qafarabic' => "\x{0642}",
- 'qaffinalarabic' => "\x{FED6}",
- 'qafinitialarabic' => "\x{FED7}",
- 'qafmedialarabic' => "\x{FED8}",
- 'qamats' => "\x{05B8}",
- 'qamats10' => "\x{05B8}",
- 'qamats1a' => "\x{05B8}",
- 'qamats1c' => "\x{05B8}",
- 'qamats27' => "\x{05B8}",
- 'qamats29' => "\x{05B8}",
- 'qamats33' => "\x{05B8}",
- 'qamatsde' => "\x{05B8}",
- 'qamatshebrew' => "\x{05B8}",
- 'qamatsnarrowhebrew' => "\x{05B8}",
- 'qamatsqatanhebrew' => "\x{05B8}",
- 'qamatsqatannarrowhebrew' => "\x{05B8}",
- 'qamatsqatanquarterhebrew' => "\x{05B8}",
- 'qamatsqatanwidehebrew' => "\x{05B8}",
- 'qamatsquarterhebrew' => "\x{05B8}",
- 'qamatswidehebrew' => "\x{05B8}",
- 'qarneyparahebrew' => "\x{059F}",
- 'qbopomofo' => "\x{3111}",
- 'qcircle' => "\x{24E0}",
- 'qhook' => "\x{02A0}",
- 'qmonospace' => "\x{FF51}",
- 'qof' => "\x{05E7}",
- 'qofdagesh' => "\x{FB47}",
- 'qofdageshhebrew' => "\x{FB47}",
- 'qofhatafpatah' => "\x{05E7}\x{05B2}",
- 'qofhatafpatahhebrew' => "\x{05E7}\x{05B2}",
- 'qofhatafsegol' => "\x{05E7}\x{05B1}",
- 'qofhatafsegolhebrew' => "\x{05E7}\x{05B1}",
- 'qofhebrew' => "\x{05E7}",
- 'qofhiriq' => "\x{05E7}\x{05B4}",
- 'qofhiriqhebrew' => "\x{05E7}\x{05B4}",
- 'qofholam' => "\x{05E7}\x{05B9}",
- 'qofholamhebrew' => "\x{05E7}\x{05B9}",
- 'qofpatah' => "\x{05E7}\x{05B7}",
- 'qofpatahhebrew' => "\x{05E7}\x{05B7}",
- 'qofqamats' => "\x{05E7}\x{05B8}",
- 'qofqamatshebrew' => "\x{05E7}\x{05B8}",
- 'qofqubuts' => "\x{05E7}\x{05BB}",
- 'qofqubutshebrew' => "\x{05E7}\x{05BB}",
- 'qofsegol' => "\x{05E7}\x{05B6}",
- 'qofsegolhebrew' => "\x{05E7}\x{05B6}",
- 'qofsheva' => "\x{05E7}\x{05B0}",
- 'qofshevahebrew' => "\x{05E7}\x{05B0}",
- 'qoftsere' => "\x{05E7}\x{05B5}",
- 'qoftserehebrew' => "\x{05E7}\x{05B5}",
- 'qparen' => "\x{24AC}",
- 'quarternote' => "\x{2669}",
- 'qubuts' => "\x{05BB}",
- 'qubuts18' => "\x{05BB}",
- 'qubuts25' => "\x{05BB}",
- 'qubuts31' => "\x{05BB}",
- 'qubutshebrew' => "\x{05BB}",
- 'qubutsnarrowhebrew' => "\x{05BB}",
- 'qubutsquarterhebrew' => "\x{05BB}",
- 'qubutswidehebrew' => "\x{05BB}",
- 'questionarabic' => "\x{061F}",
- 'questionarmenian' => "\x{055E}",
- 'questiondownsmall' => "\x{F7BF}",
- 'questiongreek' => "\x{037E}",
- 'questionmonospace' => "\x{FF1F}",
- 'questionsmall' => "\x{F73F}",
- 'quotedblmonospace' => "\x{FF02}",
- 'quotedblprime' => "\x{301E}",
- 'quotedblprimereversed' => "\x{301D}",
- 'quoteleftreversed' => "\x{201B}",
- 'quoterightn' => "\x{0149}",
- 'quotesinglemonospace' => "\x{FF07}",
- 'raarmenian' => "\x{057C}",
- 'rabengali' => "\x{09B0}",
- 'radeva' => "\x{0930}",
- 'radicalex' => "\x{F8E5}",
- 'radoverssquare' => "\x{33AE}",
- 'radoverssquaredsquare' => "\x{33AF}",
- 'radsquare' => "\x{33AD}",
- 'rafe' => "\x{05BF}",
- 'rafehebrew' => "\x{05BF}",
- 'ragujarati' => "\x{0AB0}",
- 'ragurmukhi' => "\x{0A30}",
- 'rahiragana' => "\x{3089}",
- 'rakatakana' => "\x{30E9}",
- 'rakatakanahalfwidth' => "\x{FF97}",
- 'ralowerdiagonalbengali' => "\x{09F1}",
- 'ramiddlediagonalbengali' => "\x{09F0}",
- 'ramshorn' => "\x{0264}",
- 'ratio' => "\x{2236}",
- 'rbopomofo' => "\x{3116}",
- 'rcedilla' => "\x{0157}",
- 'rcircle' => "\x{24E1}",
- 'rdblgrave' => "\x{0211}",
- 'rdotaccent' => "\x{1E59}",
- 'rdotbelow' => "\x{1E5B}",
- 'rdotbelowmacron' => "\x{1E5D}",
- 'referencemark' => "\x{203B}",
- 'registersans' => "\x{F8E8}",
- 'registerserif' => "\x{F6DA}",
- 'reharabic' => "\x{0631}",
- 'reharmenian' => "\x{0580}",
- 'rehfinalarabic' => "\x{FEAE}",
- 'rehiragana' => "\x{308C}",
- 'rehyehaleflamarabic' => "\x{0631}\x{FEF3}\x{FE8E}\x{0644}",
- 'rekatakana' => "\x{30EC}",
- 'rekatakanahalfwidth' => "\x{FF9A}",
- 'resh' => "\x{05E8}",
- 'reshdageshhebrew' => "\x{FB48}",
- 'reshhatafpatah' => "\x{05E8}\x{05B2}",
- 'reshhatafpatahhebrew' => "\x{05E8}\x{05B2}",
- 'reshhatafsegol' => "\x{05E8}\x{05B1}",
- 'reshhatafsegolhebrew' => "\x{05E8}\x{05B1}",
- 'reshhebrew' => "\x{05E8}",
- 'reshhiriq' => "\x{05E8}\x{05B4}",
- 'reshhiriqhebrew' => "\x{05E8}\x{05B4}",
- 'reshholam' => "\x{05E8}\x{05B9}",
- 'reshholamhebrew' => "\x{05E8}\x{05B9}",
- 'reshpatah' => "\x{05E8}\x{05B7}",
- 'reshpatahhebrew' => "\x{05E8}\x{05B7}",
- 'reshqamats' => "\x{05E8}\x{05B8}",
- 'reshqamatshebrew' => "\x{05E8}\x{05B8}",
- 'reshqubuts' => "\x{05E8}\x{05BB}",
- 'reshqubutshebrew' => "\x{05E8}\x{05BB}",
- 'reshsegol' => "\x{05E8}\x{05B6}",
- 'reshsegolhebrew' => "\x{05E8}\x{05B6}",
- 'reshsheva' => "\x{05E8}\x{05B0}",
- 'reshshevahebrew' => "\x{05E8}\x{05B0}",
- 'reshtsere' => "\x{05E8}\x{05B5}",
- 'reshtserehebrew' => "\x{05E8}\x{05B5}",
- 'reversedtilde' => "\x{223D}",
- 'reviahebrew' => "\x{0597}",
- 'reviamugrashhebrew' => "\x{0597}",
- 'rfishhook' => "\x{027E}",
- 'rfishhookreversed' => "\x{027F}",
- 'rhabengali' => "\x{09DD}",
- 'rhadeva' => "\x{095D}",
- 'rhook' => "\x{027D}",
- 'rhookturned' => "\x{027B}",
- 'rhookturnedsuperior' => "\x{02B5}",
- 'rhosymbolgreek' => "\x{03F1}",
- 'rhotichookmod' => "\x{02DE}",
- 'rieulacirclekorean' => "\x{3271}",
- 'rieulaparenkorean' => "\x{3211}",
- 'rieulcirclekorean' => "\x{3263}",
- 'rieulhieuhkorean' => "\x{3140}",
- 'rieulkiyeokkorean' => "\x{313A}",
- 'rieulkiyeoksioskorean' => "\x{3169}",
- 'rieulkorean' => "\x{3139}",
- 'rieulmieumkorean' => "\x{313B}",
- 'rieulpansioskorean' => "\x{316C}",
- 'rieulparenkorean' => "\x{3203}",
- 'rieulphieuphkorean' => "\x{313F}",
- 'rieulpieupkorean' => "\x{313C}",
- 'rieulpieupsioskorean' => "\x{316B}",
- 'rieulsioskorean' => "\x{313D}",
- 'rieulthieuthkorean' => "\x{313E}",
- 'rieultikeutkorean' => "\x{316A}",
- 'rieulyeorinhieuhkorean' => "\x{316D}",
- 'rightangle' => "\x{221F}",
- 'righttackbelowcmb' => "\x{0319}",
- 'righttriangle' => "\x{22BF}",
- 'rihiragana' => "\x{308A}",
- 'rikatakana' => "\x{30EA}",
- 'rikatakanahalfwidth' => "\x{FF98}",
- 'ringbelowcmb' => "\x{0325}",
- 'ringcmb' => "\x{030A}",
- 'ringhalfleft' => "\x{02BF}",
- 'ringhalfleftarmenian' => "\x{0559}",
- 'ringhalfleftbelowcmb' => "\x{031C}",
- 'ringhalfleftcentered' => "\x{02D3}",
- 'ringhalfright' => "\x{02BE}",
- 'ringhalfrightbelowcmb' => "\x{0339}",
- 'ringhalfrightcentered' => "\x{02D2}",
- 'rinvertedbreve' => "\x{0213}",
- 'rittorusquare' => "\x{3351}",
- 'rlinebelow' => "\x{1E5F}",
- 'rlongleg' => "\x{027C}",
- 'rlonglegturned' => "\x{027A}",
- 'rmonospace' => "\x{FF52}",
- 'rohiragana' => "\x{308D}",
- 'rokatakana' => "\x{30ED}",
- 'rokatakanahalfwidth' => "\x{FF9B}",
- 'roruathai' => "\x{0E23}",
- 'rparen' => "\x{24AD}",
- 'rrabengali' => "\x{09DC}",
- 'rradeva' => "\x{0931}",
- 'rragurmukhi' => "\x{0A5C}",
- 'rreharabic' => "\x{0691}",
- 'rrehfinalarabic' => "\x{FB8D}",
- 'rrvocalicbengali' => "\x{09E0}",
- 'rrvocalicdeva' => "\x{0960}",
- 'rrvocalicgujarati' => "\x{0AE0}",
- 'rrvocalicvowelsignbengali' => "\x{09C4}",
- 'rrvocalicvowelsigndeva' => "\x{0944}",
- 'rrvocalicvowelsigngujarati' => "\x{0AC4}",
- 'rsuperior' => "\x{F6F1}",
- 'rturned' => "\x{0279}",
- 'rturnedsuperior' => "\x{02B4}",
- 'ruhiragana' => "\x{308B}",
- 'rukatakana' => "\x{30EB}",
- 'rukatakanahalfwidth' => "\x{FF99}",
- 'rupeemarkbengali' => "\x{09F2}",
- 'rupeesignbengali' => "\x{09F3}",
- 'rupiah' => "\x{F6DD}",
- 'ruthai' => "\x{0E24}",
- 'rvocalicbengali' => "\x{098B}",
- 'rvocalicdeva' => "\x{090B}",
- 'rvocalicgujarati' => "\x{0A8B}",
- 'rvocalicvowelsignbengali' => "\x{09C3}",
- 'rvocalicvowelsigndeva' => "\x{0943}",
- 'rvocalicvowelsigngujarati' => "\x{0AC3}",
- 'sabengali' => "\x{09B8}",
- 'sacutedotaccent' => "\x{1E65}",
- 'sadarabic' => "\x{0635}",
- 'sadeva' => "\x{0938}",
- 'sadfinalarabic' => "\x{FEBA}",
- 'sadinitialarabic' => "\x{FEBB}",
- 'sadmedialarabic' => "\x{FEBC}",
- 'sagujarati' => "\x{0AB8}",
- 'sagurmukhi' => "\x{0A38}",
- 'sahiragana' => "\x{3055}",
- 'sakatakana' => "\x{30B5}",
- 'sakatakanahalfwidth' => "\x{FF7B}",
- 'sallallahoualayhewasallamarabic' => "\x{FDFA}",
- 'samekh' => "\x{05E1}",
- 'samekhdagesh' => "\x{FB41}",
- 'samekhdageshhebrew' => "\x{FB41}",
- 'samekhhebrew' => "\x{05E1}",
- 'saraaathai' => "\x{0E32}",
- 'saraaethai' => "\x{0E41}",
- 'saraaimaimalaithai' => "\x{0E44}",
- 'saraaimaimuanthai' => "\x{0E43}",
- 'saraamthai' => "\x{0E33}",
- 'saraathai' => "\x{0E30}",
- 'saraethai' => "\x{0E40}",
- 'saraiileftthai' => "\x{F886}",
- 'saraiithai' => "\x{0E35}",
- 'saraileftthai' => "\x{F885}",
- 'saraithai' => "\x{0E34}",
- 'saraothai' => "\x{0E42}",
- 'saraueeleftthai' => "\x{F888}",
- 'saraueethai' => "\x{0E37}",
- 'saraueleftthai' => "\x{F887}",
- 'sarauethai' => "\x{0E36}",
- 'sarauthai' => "\x{0E38}",
- 'sarauuthai' => "\x{0E39}",
- 'sbopomofo' => "\x{3119}",
- 'scarondotaccent' => "\x{1E67}",
- 'schwa' => "\x{0259}",
- 'schwacyrillic' => "\x{04D9}",
- 'schwadieresiscyrillic' => "\x{04DB}",
- 'schwahook' => "\x{025A}",
- 'scircle' => "\x{24E2}",
- 'sdotaccent' => "\x{1E61}",
- 'sdotbelow' => "\x{1E63}",
- 'sdotbelowdotaccent' => "\x{1E69}",
- 'seagullbelowcmb' => "\x{033C}",
- 'secondtonechinese' => "\x{02CA}",
- 'seenarabic' => "\x{0633}",
- 'seenfinalarabic' => "\x{FEB2}",
- 'seeninitialarabic' => "\x{FEB3}",
- 'seenmedialarabic' => "\x{FEB4}",
- 'segol' => "\x{05B6}",
- 'segol13' => "\x{05B6}",
- 'segol1f' => "\x{05B6}",
- 'segol2c' => "\x{05B6}",
- 'segolhebrew' => "\x{05B6}",
- 'segolnarrowhebrew' => "\x{05B6}",
- 'segolquarterhebrew' => "\x{05B6}",
- 'segoltahebrew' => "\x{0592}",
- 'segolwidehebrew' => "\x{05B6}",
- 'seharmenian' => "\x{057D}",
- 'sehiragana' => "\x{305B}",
- 'sekatakana' => "\x{30BB}",
- 'sekatakanahalfwidth' => "\x{FF7E}",
- 'semicolonarabic' => "\x{061B}",
- 'semicolonmonospace' => "\x{FF1B}",
- 'semicolonsmall' => "\x{FE54}",
- 'semivoicedmarkkana' => "\x{309C}",
- 'semivoicedmarkkanahalfwidth' => "\x{FF9F}",
- 'sentisquare' => "\x{3322}",
- 'sentosquare' => "\x{3323}",
- 'sevenarabic' => "\x{0667}",
- 'sevenbengali' => "\x{09ED}",
- 'sevencircle' => "\x{2466}",
- 'sevencircleinversesansserif' => "\x{2790}",
- 'sevendeva' => "\x{096D}",
- 'sevengujarati' => "\x{0AED}",
- 'sevengurmukhi' => "\x{0A6D}",
- 'sevenhackarabic' => "\x{0667}",
- 'sevenhangzhou' => "\x{3027}",
- 'sevenideographicparen' => "\x{3226}",
- 'seveninferior' => "\x{2087}",
- 'sevenmonospace' => "\x{FF17}",
- 'sevenoldstyle' => "\x{F737}",
- 'sevenparen' => "\x{247A}",
- 'sevenperiod' => "\x{248E}",
- 'sevenpersian' => "\x{06F7}",
- 'sevenroman' => "\x{2176}",
- 'sevensuperior' => "\x{2077}",
- 'seventeencircle' => "\x{2470}",
- 'seventeenparen' => "\x{2484}",
- 'seventeenperiod' => "\x{2498}",
- 'seventhai' => "\x{0E57}",
- 'sfthyphen' => "\x{00AD}",
- 'shaarmenian' => "\x{0577}",
- 'shabengali' => "\x{09B6}",
- 'shacyrillic' => "\x{0448}",
- 'shaddaarabic' => "\x{0651}",
- 'shaddadammaarabic' => "\x{FC61}",
- 'shaddadammatanarabic' => "\x{FC5E}",
- 'shaddafathaarabic' => "\x{FC60}",
- 'shaddafathatanarabic' => "\x{0651}\x{064B}",
- 'shaddakasraarabic' => "\x{FC62}",
- 'shaddakasratanarabic' => "\x{FC5F}",
- 'shadedark' => "\x{2593}",
- 'shadelight' => "\x{2591}",
- 'shademedium' => "\x{2592}",
- 'shadeva' => "\x{0936}",
- 'shagujarati' => "\x{0AB6}",
- 'shagurmukhi' => "\x{0A36}",
- 'shalshelethebrew' => "\x{0593}",
- 'shbopomofo' => "\x{3115}",
- 'shchacyrillic' => "\x{0449}",
- 'sheenarabic' => "\x{0634}",
- 'sheenfinalarabic' => "\x{FEB6}",
- 'sheeninitialarabic' => "\x{FEB7}",
- 'sheenmedialarabic' => "\x{FEB8}",
- 'sheicoptic' => "\x{03E3}",
- 'sheqel' => "\x{20AA}",
- 'sheqelhebrew' => "\x{20AA}",
- 'sheva' => "\x{05B0}",
- 'sheva115' => "\x{05B0}",
- 'sheva15' => "\x{05B0}",
- 'sheva22' => "\x{05B0}",
- 'sheva2e' => "\x{05B0}",
- 'shevahebrew' => "\x{05B0}",
- 'shevanarrowhebrew' => "\x{05B0}",
- 'shevaquarterhebrew' => "\x{05B0}",
- 'shevawidehebrew' => "\x{05B0}",
- 'shhacyrillic' => "\x{04BB}",
- 'shimacoptic' => "\x{03ED}",
- 'shin' => "\x{05E9}",
- 'shindagesh' => "\x{FB49}",
- 'shindageshhebrew' => "\x{FB49}",
- 'shindageshshindot' => "\x{FB2C}",
- 'shindageshshindothebrew' => "\x{FB2C}",
- 'shindageshsindot' => "\x{FB2D}",
- 'shindageshsindothebrew' => "\x{FB2D}",
- 'shindothebrew' => "\x{05C1}",
- 'shinhebrew' => "\x{05E9}",
- 'shinshindot' => "\x{FB2A}",
- 'shinshindothebrew' => "\x{FB2A}",
- 'shinsindot' => "\x{FB2B}",
- 'shinsindothebrew' => "\x{FB2B}",
- 'shook' => "\x{0282}",
- 'sigmafinal' => "\x{03C2}",
- 'sigmalunatesymbolgreek' => "\x{03F2}",
- 'sihiragana' => "\x{3057}",
- 'sikatakana' => "\x{30B7}",
- 'sikatakanahalfwidth' => "\x{FF7C}",
- 'siluqhebrew' => "\x{05BD}",
- 'siluqlefthebrew' => "\x{05BD}",
- 'sindothebrew' => "\x{05C2}",
- 'siosacirclekorean' => "\x{3274}",
- 'siosaparenkorean' => "\x{3214}",
- 'sioscieuckorean' => "\x{317E}",
- 'sioscirclekorean' => "\x{3266}",
- 'sioskiyeokkorean' => "\x{317A}",
- 'sioskorean' => "\x{3145}",
- 'siosnieunkorean' => "\x{317B}",
- 'siosparenkorean' => "\x{3206}",
- 'siospieupkorean' => "\x{317D}",
- 'siostikeutkorean' => "\x{317C}",
- 'sixarabic' => "\x{0666}",
- 'sixbengali' => "\x{09EC}",
- 'sixcircle' => "\x{2465}",
- 'sixcircleinversesansserif' => "\x{278F}",
- 'sixdeva' => "\x{096C}",
- 'sixgujarati' => "\x{0AEC}",
- 'sixgurmukhi' => "\x{0A6C}",
- 'sixhackarabic' => "\x{0666}",
- 'sixhangzhou' => "\x{3026}",
- 'sixideographicparen' => "\x{3225}",
- 'sixinferior' => "\x{2086}",
- 'sixmonospace' => "\x{FF16}",
- 'sixoldstyle' => "\x{F736}",
- 'sixparen' => "\x{2479}",
- 'sixperiod' => "\x{248D}",
- 'sixpersian' => "\x{06F6}",
- 'sixroman' => "\x{2175}",
- 'sixsuperior' => "\x{2076}",
- 'sixteencircle' => "\x{246F}",
- 'sixteencurrencydenominatorbengali' => "\x{09F9}",
- 'sixteenparen' => "\x{2483}",
- 'sixteenperiod' => "\x{2497}",
- 'sixthai' => "\x{0E56}",
- 'slashmonospace' => "\x{FF0F}",
- 'slong' => "\x{017F}",
- 'slongdotaccent' => "\x{1E9B}",
- 'smonospace' => "\x{FF53}",
- 'sofpasuqhebrew' => "\x{05C3}",
- 'softhyphen' => "\x{00AD}",
- 'softsigncyrillic' => "\x{044C}",
- 'sohiragana' => "\x{305D}",
- 'sokatakana' => "\x{30BD}",
- 'sokatakanahalfwidth' => "\x{FF7F}",
- 'soliduslongoverlaycmb' => "\x{0338}",
- 'solidusshortoverlaycmb' => "\x{0337}",
- 'sorusithai' => "\x{0E29}",
- 'sosalathai' => "\x{0E28}",
- 'sosothai' => "\x{0E0B}",
- 'sosuathai' => "\x{0E2A}",
- 'spacehackarabic' => "\x{0020}",
- 'spadesuitblack' => "\x{2660}",
- 'spadesuitwhite' => "\x{2664}",
- 'sparen' => "\x{24AE}",
- 'squarebelowcmb' => "\x{033B}",
- 'squarecc' => "\x{33C4}",
- 'squarecm' => "\x{339D}",
- 'squarediagonalcrosshatchfill' => "\x{25A9}",
- 'squarehorizontalfill' => "\x{25A4}",
- 'squarekg' => "\x{338F}",
- 'squarekm' => "\x{339E}",
- 'squarekmcapital' => "\x{33CE}",
- 'squareln' => "\x{33D1}",
- 'squarelog' => "\x{33D2}",
- 'squaremg' => "\x{338E}",
- 'squaremil' => "\x{33D5}",
- 'squaremm' => "\x{339C}",
- 'squaremsquared' => "\x{33A1}",
- 'squareorthogonalcrosshatchfill' => "\x{25A6}",
- 'squareupperlefttolowerrightfill' => "\x{25A7}",
- 'squareupperrighttolowerleftfill' => "\x{25A8}",
- 'squareverticalfill' => "\x{25A5}",
- 'squarewhitewithsmallblack' => "\x{25A3}",
- 'srsquare' => "\x{33DB}",
- 'ssabengali' => "\x{09B7}",
- 'ssadeva' => "\x{0937}",
- 'ssagujarati' => "\x{0AB7}",
- 'ssangcieuckorean' => "\x{3149}",
- 'ssanghieuhkorean' => "\x{3185}",
- 'ssangieungkorean' => "\x{3180}",
- 'ssangkiyeokkorean' => "\x{3132}",
- 'ssangnieunkorean' => "\x{3165}",
- 'ssangpieupkorean' => "\x{3143}",
- 'ssangsioskorean' => "\x{3146}",
- 'ssangtikeutkorean' => "\x{3138}",
- 'ssuperior' => "\x{F6F2}",
- 'sterlingmonospace' => "\x{FFE1}",
- 'strokelongoverlaycmb' => "\x{0336}",
- 'strokeshortoverlaycmb' => "\x{0335}",
- 'subset' => "\x{2282}",
- 'subsetnotequal' => "\x{228A}",
- 'subsetorequal' => "\x{2286}",
- 'succeeds' => "\x{227B}",
- 'suhiragana' => "\x{3059}",
- 'sukatakana' => "\x{30B9}",
- 'sukatakanahalfwidth' => "\x{FF7D}",
- 'sukunarabic' => "\x{0652}",
- 'superset' => "\x{2283}",
- 'supersetnotequal' => "\x{228B}",
- 'supersetorequal' => "\x{2287}",
- 'svsquare' => "\x{33DC}",
- 'syouwaerasquare' => "\x{337C}",
- 'tabengali' => "\x{09A4}",
- 'tackdown' => "\x{22A4}",
- 'tackleft' => "\x{22A3}",
- 'tadeva' => "\x{0924}",
- 'tagujarati' => "\x{0AA4}",
- 'tagurmukhi' => "\x{0A24}",
- 'taharabic' => "\x{0637}",
- 'tahfinalarabic' => "\x{FEC2}",
- 'tahinitialarabic' => "\x{FEC3}",
- 'tahiragana' => "\x{305F}",
- 'tahmedialarabic' => "\x{FEC4}",
- 'taisyouerasquare' => "\x{337D}",
- 'takatakana' => "\x{30BF}",
- 'takatakanahalfwidth' => "\x{FF80}",
- 'tatweelarabic' => "\x{0640}",
- 'tav' => "\x{05EA}",
- 'tavdages' => "\x{FB4A}",
- 'tavdagesh' => "\x{FB4A}",
- 'tavdageshhebrew' => "\x{FB4A}",
- 'tavhebrew' => "\x{05EA}",
- 'tbopomofo' => "\x{310A}",
- 'tccurl' => "\x{02A8}",
- 'tcedilla' => "\x{0163}",
- 'tcheharabic' => "\x{0686}",
- 'tchehfinalarabic' => "\x{FB7B}",
- 'tchehinitialarabic' => "\x{FB7C}",
- 'tchehmedialarabic' => "\x{FB7D}",
- 'tchehmeeminitialarabic' => "\x{FB7C}\x{FEE4}",
- 'tcircle' => "\x{24E3}",
- 'tcircumflexbelow' => "\x{1E71}",
- 'tdieresis' => "\x{1E97}",
- 'tdotaccent' => "\x{1E6B}",
- 'tdotbelow' => "\x{1E6D}",
- 'tecyrillic' => "\x{0442}",
- 'tedescendercyrillic' => "\x{04AD}",
- 'teharabic' => "\x{062A}",
- 'tehfinalarabic' => "\x{FE96}",
- 'tehhahinitialarabic' => "\x{FCA2}",
- 'tehhahisolatedarabic' => "\x{FC0C}",
- 'tehinitialarabic' => "\x{FE97}",
- 'tehiragana' => "\x{3066}",
- 'tehjeeminitialarabic' => "\x{FCA1}",
- 'tehjeemisolatedarabic' => "\x{FC0B}",
- 'tehmarbutaarabic' => "\x{0629}",
- 'tehmarbutafinalarabic' => "\x{FE94}",
- 'tehmedialarabic' => "\x{FE98}",
- 'tehmeeminitialarabic' => "\x{FCA4}",
- 'tehmeemisolatedarabic' => "\x{FC0E}",
- 'tehnoonfinalarabic' => "\x{FC73}",
- 'tekatakana' => "\x{30C6}",
- 'tekatakanahalfwidth' => "\x{FF83}",
- 'telephone' => "\x{2121}",
- 'telephoneblack' => "\x{260E}",
- 'telishagedolahebrew' => "\x{05A0}",
- 'telishaqetanahebrew' => "\x{05A9}",
- 'tencircle' => "\x{2469}",
- 'tenideographicparen' => "\x{3229}",
- 'tenparen' => "\x{247D}",
- 'tenperiod' => "\x{2491}",
- 'tenroman' => "\x{2179}",
- 'tesh' => "\x{02A7}",
- 'tet' => "\x{05D8}",
- 'tetdagesh' => "\x{FB38}",
- 'tetdageshhebrew' => "\x{FB38}",
- 'tethebrew' => "\x{05D8}",
- 'tetsecyrillic' => "\x{04B5}",
- 'tevirhebrew' => "\x{059B}",
- 'tevirlefthebrew' => "\x{059B}",
- 'thabengali' => "\x{09A5}",
- 'thadeva' => "\x{0925}",
- 'thagujarati' => "\x{0AA5}",
- 'thagurmukhi' => "\x{0A25}",
- 'thalarabic' => "\x{0630}",
- 'thalfinalarabic' => "\x{FEAC}",
- 'thanthakhatlowleftthai' => "\x{F898}",
- 'thanthakhatlowrightthai' => "\x{F897}",
- 'thanthakhatthai' => "\x{0E4C}",
- 'thanthakhatupperleftthai' => "\x{F896}",
- 'theharabic' => "\x{062B}",
- 'thehfinalarabic' => "\x{FE9A}",
- 'thehinitialarabic' => "\x{FE9B}",
- 'thehmedialarabic' => "\x{FE9C}",
- 'thereexists' => "\x{2203}",
- 'thetasymbolgreek' => "\x{03D1}",
- 'thieuthacirclekorean' => "\x{3279}",
- 'thieuthaparenkorean' => "\x{3219}",
- 'thieuthcirclekorean' => "\x{326B}",
- 'thieuthkorean' => "\x{314C}",
- 'thieuthparenkorean' => "\x{320B}",
- 'thirteencircle' => "\x{246C}",
- 'thirteenparen' => "\x{2480}",
- 'thirteenperiod' => "\x{2494}",
- 'thonangmonthothai' => "\x{0E11}",
- 'thook' => "\x{01AD}",
- 'thophuthaothai' => "\x{0E12}",
- 'thothahanthai' => "\x{0E17}",
- 'thothanthai' => "\x{0E10}",
- 'thothongthai' => "\x{0E18}",
- 'thothungthai' => "\x{0E16}",
- 'thousandcyrillic' => "\x{0482}",
- 'thousandsseparatorarabic' => "\x{066C}",
- 'thousandsseparatorpersian' => "\x{066C}",
- 'threearabic' => "\x{0663}",
- 'threebengali' => "\x{09E9}",
- 'threecircle' => "\x{2462}",
- 'threecircleinversesansserif' => "\x{278C}",
- 'threedeva' => "\x{0969}",
- 'threegujarati' => "\x{0AE9}",
- 'threegurmukhi' => "\x{0A69}",
- 'threehackarabic' => "\x{0663}",
- 'threehangzhou' => "\x{3023}",
- 'threeideographicparen' => "\x{3222}",
- 'threeinferior' => "\x{2083}",
- 'threemonospace' => "\x{FF13}",
- 'threenumeratorbengali' => "\x{09F6}",
- 'threeoldstyle' => "\x{F733}",
- 'threeparen' => "\x{2476}",
- 'threeperiod' => "\x{248A}",
- 'threepersian' => "\x{06F3}",
- 'threequartersemdash' => "\x{F6DE}",
- 'threeroman' => "\x{2172}",
- 'threethai' => "\x{0E53}",
- 'thzsquare' => "\x{3394}",
- 'tihiragana' => "\x{3061}",
- 'tikatakana' => "\x{30C1}",
- 'tikatakanahalfwidth' => "\x{FF81}",
- 'tikeutacirclekorean' => "\x{3270}",
- 'tikeutaparenkorean' => "\x{3210}",
- 'tikeutcirclekorean' => "\x{3262}",
- 'tikeutkorean' => "\x{3137}",
- 'tikeutparenkorean' => "\x{3202}",
- 'tildebelowcmb' => "\x{0330}",
- 'tildecmb' => "\x{0303}",
- 'tildedoublecmb' => "\x{0360}",
- 'tildeoperator' => "\x{223C}",
- 'tildeoverlaycmb' => "\x{0334}",
- 'tildeverticalcmb' => "\x{033E}",
- 'timescircle' => "\x{2297}",
- 'tipehahebrew' => "\x{0596}",
- 'tipehalefthebrew' => "\x{0596}",
- 'tippigurmukhi' => "\x{0A70}",
- 'titlocyrilliccmb' => "\x{0483}",
- 'tiwnarmenian' => "\x{057F}",
- 'tlinebelow' => "\x{1E6F}",
- 'tmonospace' => "\x{FF54}",
- 'toarmenian' => "\x{0569}",
- 'tohiragana' => "\x{3068}",
- 'tokatakana' => "\x{30C8}",
- 'tokatakanahalfwidth' => "\x{FF84}",
- 'tonebarextrahighmod' => "\x{02E5}",
- 'tonebarextralowmod' => "\x{02E9}",
- 'tonebarhighmod' => "\x{02E6}",
- 'tonebarlowmod' => "\x{02E8}",
- 'tonebarmidmod' => "\x{02E7}",
- 'tonefive' => "\x{01BD}",
- 'tonesix' => "\x{0185}",
- 'tonetwo' => "\x{01A8}",
- 'tonsquare' => "\x{3327}",
- 'topatakthai' => "\x{0E0F}",
- 'tortoiseshellbracketleft' => "\x{3014}",
- 'tortoiseshellbracketleftsmall' => "\x{FE5D}",
- 'tortoiseshellbracketleftvertical' => "\x{FE39}",
- 'tortoiseshellbracketright' => "\x{3015}",
- 'tortoiseshellbracketrightsmall' => "\x{FE5E}",
- 'tortoiseshellbracketrightvertical' => "\x{FE3A}",
- 'totaothai' => "\x{0E15}",
- 'tpalatalhook' => "\x{01AB}",
- 'tparen' => "\x{24AF}",
- 'trademarksans' => "\x{F8EA}",
- 'trademarkserif' => "\x{F6DB}",
- 'tretroflexhook' => "\x{0288}",
- 'ts' => "\x{02A6}",
- 'tsadi' => "\x{05E6}",
- 'tsadidagesh' => "\x{FB46}",
- 'tsadidageshhebrew' => "\x{FB46}",
- 'tsadihebrew' => "\x{05E6}",
- 'tsecyrillic' => "\x{0446}",
- 'tsere' => "\x{05B5}",
- 'tsere12' => "\x{05B5}",
- 'tsere1e' => "\x{05B5}",
- 'tsere2b' => "\x{05B5}",
- 'tserehebrew' => "\x{05B5}",
- 'tserenarrowhebrew' => "\x{05B5}",
- 'tserequarterhebrew' => "\x{05B5}",
- 'tserewidehebrew' => "\x{05B5}",
- 'tshecyrillic' => "\x{045B}",
- 'tsuperior' => "\x{F6F3}",
- 'ttabengali' => "\x{099F}",
- 'ttadeva' => "\x{091F}",
- 'ttagujarati' => "\x{0A9F}",
- 'ttagurmukhi' => "\x{0A1F}",
- 'tteharabic' => "\x{0679}",
- 'ttehfinalarabic' => "\x{FB67}",
- 'ttehinitialarabic' => "\x{FB68}",
- 'ttehmedialarabic' => "\x{FB69}",
- 'tthabengali' => "\x{09A0}",
- 'tthadeva' => "\x{0920}",
- 'tthagujarati' => "\x{0AA0}",
- 'tthagurmukhi' => "\x{0A20}",
- 'tturned' => "\x{0287}",
- 'tuhiragana' => "\x{3064}",
- 'tukatakana' => "\x{30C4}",
- 'tukatakanahalfwidth' => "\x{FF82}",
- 'tusmallhiragana' => "\x{3063}",
- 'tusmallkatakana' => "\x{30C3}",
- 'tusmallkatakanahalfwidth' => "\x{FF6F}",
- 'twelvecircle' => "\x{246B}",
- 'twelveparen' => "\x{247F}",
- 'twelveperiod' => "\x{2493}",
- 'twelveroman' => "\x{217B}",
- 'twentycircle' => "\x{2473}",
- 'twentyhangzhou' => "\x{5344}",
- 'twentyparen' => "\x{2487}",
- 'twentyperiod' => "\x{249B}",
- 'twoarabic' => "\x{0662}",
- 'twobengali' => "\x{09E8}",
- 'twocircle' => "\x{2461}",
- 'twocircleinversesansserif' => "\x{278B}",
- 'twodeva' => "\x{0968}",
- 'twodotleader' => "\x{2025}",
- 'twodotleadervertical' => "\x{FE30}",
- 'twogujarati' => "\x{0AE8}",
- 'twogurmukhi' => "\x{0A68}",
- 'twohackarabic' => "\x{0662}",
- 'twohangzhou' => "\x{3022}",
- 'twoideographicparen' => "\x{3221}",
- 'twoinferior' => "\x{2082}",
- 'twomonospace' => "\x{FF12}",
- 'twonumeratorbengali' => "\x{09F5}",
- 'twooldstyle' => "\x{F732}",
- 'twoparen' => "\x{2475}",
- 'twoperiod' => "\x{2489}",
- 'twopersian' => "\x{06F2}",
- 'tworoman' => "\x{2171}",
- 'twostroke' => "\x{01BB}",
- 'twothai' => "\x{0E52}",
- 'ubar' => "\x{0289}",
- 'ubengali' => "\x{0989}",
- 'ubopomofo' => "\x{3128}",
- 'ucaron' => "\x{01D4}",
- 'ucircle' => "\x{24E4}",
- 'ucircumflexbelow' => "\x{1E77}",
- 'ucyrillic' => "\x{0443}",
- 'udattadeva' => "\x{0951}",
- 'udblacute' => "\x{0171}",
- 'udblgrave' => "\x{0215}",
- 'udeva' => "\x{0909}",
- 'udieresisacute' => "\x{01D8}",
- 'udieresisbelow' => "\x{1E73}",
- 'udieresiscaron' => "\x{01DA}",
- 'udieresiscyrillic' => "\x{04F1}",
- 'udieresisgrave' => "\x{01DC}",
- 'udieresismacron' => "\x{01D6}",
- 'udotbelow' => "\x{1EE5}",
- 'ugujarati' => "\x{0A89}",
- 'ugurmukhi' => "\x{0A09}",
- 'uhiragana' => "\x{3046}",
- 'uhookabove' => "\x{1EE7}",
- 'uhornacute' => "\x{1EE9}",
- 'uhorndotbelow' => "\x{1EF1}",
- 'uhorngrave' => "\x{1EEB}",
- 'uhornhookabove' => "\x{1EED}",
- 'uhorntilde' => "\x{1EEF}",
- 'uhungarumlautcyrillic' => "\x{04F3}",
- 'uinvertedbreve' => "\x{0217}",
- 'ukatakana' => "\x{30A6}",
- 'ukatakanahalfwidth' => "\x{FF73}",
- 'ukcyrillic' => "\x{0479}",
- 'ukorean' => "\x{315C}",
- 'umacroncyrillic' => "\x{04EF}",
- 'umacrondieresis' => "\x{1E7B}",
- 'umatragurmukhi' => "\x{0A41}",
- 'umonospace' => "\x{FF55}",
- 'underscoremonospace' => "\x{FF3F}",
- 'underscorevertical' => "\x{FE33}",
- 'underscorewavy' => "\x{FE4F}",
- 'uparen' => "\x{24B0}",
- 'upperdothebrew' => "\x{05C4}",
- 'upsilonlatin' => "\x{028A}",
- 'uptackbelowcmb' => "\x{031D}",
- 'uptackmod' => "\x{02D4}",
- 'uragurmukhi' => "\x{0A73}",
- 'ushortcyrillic' => "\x{045E}",
- 'usmallhiragana' => "\x{3045}",
- 'usmallkatakana' => "\x{30A5}",
- 'usmallkatakanahalfwidth' => "\x{FF69}",
- 'ustraightcyrillic' => "\x{04AF}",
- 'ustraightstrokecyrillic' => "\x{04B1}",
- 'utildeacute' => "\x{1E79}",
- 'utildebelow' => "\x{1E75}",
- 'uubengali' => "\x{098A}",
- 'uudeva' => "\x{090A}",
- 'uugujarati' => "\x{0A8A}",
- 'uugurmukhi' => "\x{0A0A}",
- 'uumatragurmukhi' => "\x{0A42}",
- 'uuvowelsignbengali' => "\x{09C2}",
- 'uuvowelsigndeva' => "\x{0942}",
- 'uuvowelsigngujarati' => "\x{0AC2}",
- 'uvowelsignbengali' => "\x{09C1}",
- 'uvowelsigndeva' => "\x{0941}",
- 'uvowelsigngujarati' => "\x{0AC1}",
- 'vadeva' => "\x{0935}",
- 'vagujarati' => "\x{0AB5}",
- 'vagurmukhi' => "\x{0A35}",
- 'vakatakana' => "\x{30F7}",
- 'vav' => "\x{05D5}",
- 'vavdagesh' => "\x{FB35}",
- 'vavdagesh65' => "\x{FB35}",
- 'vavdageshhebrew' => "\x{FB35}",
- 'vavhebrew' => "\x{05D5}",
- 'vavholam' => "\x{FB4B}",
- 'vavholamhebrew' => "\x{FB4B}",
- 'vavvavhebrew' => "\x{05F0}",
- 'vavyodhebrew' => "\x{05F1}",
- 'vcircle' => "\x{24E5}",
- 'vdotbelow' => "\x{1E7F}",
- 'vecyrillic' => "\x{0432}",
- 'veharabic' => "\x{06A4}",
- 'vehfinalarabic' => "\x{FB6B}",
- 'vehinitialarabic' => "\x{FB6C}",
- 'vehmedialarabic' => "\x{FB6D}",
- 'vekatakana' => "\x{30F9}",
- 'venus' => "\x{2640}",
- 'verticalbar' => "\x{007C}",
- 'verticallineabovecmb' => "\x{030D}",
- 'verticallinebelowcmb' => "\x{0329}",
- 'verticallinelowmod' => "\x{02CC}",
- 'verticallinemod' => "\x{02C8}",
- 'vewarmenian' => "\x{057E}",
- 'vhook' => "\x{028B}",
- 'vikatakana' => "\x{30F8}",
- 'viramabengali' => "\x{09CD}",
- 'viramadeva' => "\x{094D}",
- 'viramagujarati' => "\x{0ACD}",
- 'visargabengali' => "\x{0983}",
- 'visargadeva' => "\x{0903}",
- 'visargagujarati' => "\x{0A83}",
- 'vmonospace' => "\x{FF56}",
- 'voarmenian' => "\x{0578}",
- 'voicediterationhiragana' => "\x{309E}",
- 'voicediterationkatakana' => "\x{30FE}",
- 'voicedmarkkana' => "\x{309B}",
- 'voicedmarkkanahalfwidth' => "\x{FF9E}",
- 'vokatakana' => "\x{30FA}",
- 'vparen' => "\x{24B1}",
- 'vtilde' => "\x{1E7D}",
- 'vturned' => "\x{028C}",
- 'vuhiragana' => "\x{3094}",
- 'vukatakana' => "\x{30F4}",
- 'waekorean' => "\x{3159}",
- 'wahiragana' => "\x{308F}",
- 'wakatakana' => "\x{30EF}",
- 'wakatakanahalfwidth' => "\x{FF9C}",
- 'wakorean' => "\x{3158}",
- 'wasmallhiragana' => "\x{308E}",
- 'wasmallkatakana' => "\x{30EE}",
- 'wattosquare' => "\x{3357}",
- 'wavedash' => "\x{301C}",
- 'wavyunderscorevertical' => "\x{FE34}",
- 'wawarabic' => "\x{0648}",
- 'wawfinalarabic' => "\x{FEEE}",
- 'wawhamzaabovearabic' => "\x{0624}",
- 'wawhamzaabovefinalarabic' => "\x{FE86}",
- 'wbsquare' => "\x{33DD}",
- 'wcircle' => "\x{24E6}",
- 'wdotaccent' => "\x{1E87}",
- 'wdotbelow' => "\x{1E89}",
- 'wehiragana' => "\x{3091}",
- 'wekatakana' => "\x{30F1}",
- 'wekorean' => "\x{315E}",
- 'weokorean' => "\x{315D}",
- 'whitebullet' => "\x{25E6}",
- 'whitecircle' => "\x{25CB}",
- 'whitecircleinverse' => "\x{25D9}",
- 'whitecornerbracketleft' => "\x{300E}",
- 'whitecornerbracketleftvertical' => "\x{FE43}",
- 'whitecornerbracketright' => "\x{300F}",
- 'whitecornerbracketrightvertical' => "\x{FE44}",
- 'whitediamond' => "\x{25C7}",
- 'whitediamondcontainingblacksmalldiamond' => "\x{25C8}",
- 'whitedownpointingsmalltriangle' => "\x{25BF}",
- 'whitedownpointingtriangle' => "\x{25BD}",
- 'whiteleftpointingsmalltriangle' => "\x{25C3}",
- 'whiteleftpointingtriangle' => "\x{25C1}",
- 'whitelenticularbracketleft' => "\x{3016}",
- 'whitelenticularbracketright' => "\x{3017}",
- 'whiterightpointingsmalltriangle' => "\x{25B9}",
- 'whiterightpointingtriangle' => "\x{25B7}",
- 'whitesmallsquare' => "\x{25AB}",
- 'whitesmilingface' => "\x{263A}",
- 'whitesquare' => "\x{25A1}",
- 'whitestar' => "\x{2606}",
- 'whitetelephone' => "\x{260F}",
- 'whitetortoiseshellbracketleft' => "\x{3018}",
- 'whitetortoiseshellbracketright' => "\x{3019}",
- 'whiteuppointingsmalltriangle' => "\x{25B5}",
- 'whiteuppointingtriangle' => "\x{25B3}",
- 'wihiragana' => "\x{3090}",
- 'wikatakana' => "\x{30F0}",
- 'wikorean' => "\x{315F}",
- 'wmonospace' => "\x{FF57}",
- 'wohiragana' => "\x{3092}",
- 'wokatakana' => "\x{30F2}",
- 'wokatakanahalfwidth' => "\x{FF66}",
- 'won' => "\x{20A9}",
- 'wonmonospace' => "\x{FFE6}",
- 'wowaenthai' => "\x{0E27}",
- 'wparen' => "\x{24B2}",
- 'wring' => "\x{1E98}",
- 'wsuperior' => "\x{02B7}",
- 'wturned' => "\x{028D}",
- 'wynn' => "\x{01BF}",
- 'xabovecmb' => "\x{033D}",
- 'xbopomofo' => "\x{3112}",
- 'xcircle' => "\x{24E7}",
- 'xdieresis' => "\x{1E8D}",
- 'xdotaccent' => "\x{1E8B}",
- 'xeharmenian' => "\x{056D}",
- 'xmonospace' => "\x{FF58}",
- 'xparen' => "\x{24B3}",
- 'xsuperior' => "\x{02E3}",
- 'yaadosquare' => "\x{334E}",
- 'yabengali' => "\x{09AF}",
- 'yadeva' => "\x{092F}",
- 'yaekorean' => "\x{3152}",
- 'yagujarati' => "\x{0AAF}",
- 'yagurmukhi' => "\x{0A2F}",
- 'yahiragana' => "\x{3084}",
- 'yakatakana' => "\x{30E4}",
- 'yakatakanahalfwidth' => "\x{FF94}",
- 'yakorean' => "\x{3151}",
- 'yamakkanthai' => "\x{0E4E}",
- 'yasmallhiragana' => "\x{3083}",
- 'yasmallkatakana' => "\x{30E3}",
- 'yasmallkatakanahalfwidth' => "\x{FF6C}",
- 'yatcyrillic' => "\x{0463}",
- 'ycircle' => "\x{24E8}",
- 'ydotaccent' => "\x{1E8F}",
- 'ydotbelow' => "\x{1EF5}",
- 'yeharabic' => "\x{064A}",
- 'yehbarreearabic' => "\x{06D2}",
- 'yehbarreefinalarabic' => "\x{FBAF}",
- 'yehfinalarabic' => "\x{FEF2}",
- 'yehhamzaabovearabic' => "\x{0626}",
- 'yehhamzaabovefinalarabic' => "\x{FE8A}",
- 'yehhamzaaboveinitialarabic' => "\x{FE8B}",
- 'yehhamzaabovemedialarabic' => "\x{FE8C}",
- 'yehinitialarabic' => "\x{FEF3}",
- 'yehmedialarabic' => "\x{FEF4}",
- 'yehmeeminitialarabic' => "\x{FCDD}",
- 'yehmeemisolatedarabic' => "\x{FC58}",
- 'yehnoonfinalarabic' => "\x{FC94}",
- 'yehthreedotsbelowarabic' => "\x{06D1}",
- 'yekorean' => "\x{3156}",
- 'yenmonospace' => "\x{FFE5}",
- 'yeokorean' => "\x{3155}",
- 'yeorinhieuhkorean' => "\x{3186}",
- 'yerahbenyomohebrew' => "\x{05AA}",
- 'yerahbenyomolefthebrew' => "\x{05AA}",
- 'yericyrillic' => "\x{044B}",
- 'yerudieresiscyrillic' => "\x{04F9}",
- 'yesieungkorean' => "\x{3181}",
- 'yesieungpansioskorean' => "\x{3183}",
- 'yesieungsioskorean' => "\x{3182}",
- 'yetivhebrew' => "\x{059A}",
- 'yhook' => "\x{01B4}",
- 'yhookabove' => "\x{1EF7}",
- 'yiarmenian' => "\x{0575}",
- 'yicyrillic' => "\x{0457}",
- 'yikorean' => "\x{3162}",
- 'yinyang' => "\x{262F}",
- 'yiwnarmenian' => "\x{0582}",
- 'ymonospace' => "\x{FF59}",
- 'yod' => "\x{05D9}",
- 'yoddagesh' => "\x{FB39}",
- 'yoddageshhebrew' => "\x{FB39}",
- 'yodhebrew' => "\x{05D9}",
- 'yodyodhebrew' => "\x{05F2}",
- 'yodyodpatahhebrew' => "\x{FB1F}",
- 'yohiragana' => "\x{3088}",
- 'yoikorean' => "\x{3189}",
- 'yokatakana' => "\x{30E8}",
- 'yokatakanahalfwidth' => "\x{FF96}",
- 'yokorean' => "\x{315B}",
- 'yosmallhiragana' => "\x{3087}",
- 'yosmallkatakana' => "\x{30E7}",
- 'yosmallkatakanahalfwidth' => "\x{FF6E}",
- 'yotgreek' => "\x{03F3}",
- 'yoyaekorean' => "\x{3188}",
- 'yoyakorean' => "\x{3187}",
- 'yoyakthai' => "\x{0E22}",
- 'yoyingthai' => "\x{0E0D}",
- 'yparen' => "\x{24B4}",
- 'ypogegrammeni' => "\x{037A}",
- 'ypogegrammenigreekcmb' => "\x{0345}",
- 'yr' => "\x{01A6}",
- 'yring' => "\x{1E99}",
- 'ysuperior' => "\x{02B8}",
- 'ytilde' => "\x{1EF9}",
- 'yturned' => "\x{028E}",
- 'yuhiragana' => "\x{3086}",
- 'yuikorean' => "\x{318C}",
- 'yukatakana' => "\x{30E6}",
- 'yukatakanahalfwidth' => "\x{FF95}",
- 'yukorean' => "\x{3160}",
- 'yusbigcyrillic' => "\x{046B}",
- 'yusbigiotifiedcyrillic' => "\x{046D}",
- 'yuslittlecyrillic' => "\x{0467}",
- 'yuslittleiotifiedcyrillic' => "\x{0469}",
- 'yusmallhiragana' => "\x{3085}",
- 'yusmallkatakana' => "\x{30E5}",
- 'yusmallkatakanahalfwidth' => "\x{FF6D}",
- 'yuyekorean' => "\x{318B}",
- 'yuyeokorean' => "\x{318A}",
- 'yyabengali' => "\x{09DF}",
- 'yyadeva' => "\x{095F}",
- 'zaarmenian' => "\x{0566}",
- 'zadeva' => "\x{095B}",
- 'zagurmukhi' => "\x{0A5B}",
- 'zaharabic' => "\x{0638}",
- 'zahfinalarabic' => "\x{FEC6}",
- 'zahinitialarabic' => "\x{FEC7}",
- 'zahiragana' => "\x{3056}",
- 'zahmedialarabic' => "\x{FEC8}",
- 'zainarabic' => "\x{0632}",
- 'zainfinalarabic' => "\x{FEB0}",
- 'zakatakana' => "\x{30B6}",
- 'zaqefgadolhebrew' => "\x{0595}",
- 'zaqefqatanhebrew' => "\x{0594}",
- 'zarqahebrew' => "\x{0598}",
- 'zayin' => "\x{05D6}",
- 'zayindagesh' => "\x{FB36}",
- 'zayindageshhebrew' => "\x{FB36}",
- 'zayinhebrew' => "\x{05D6}",
- 'zbopomofo' => "\x{3117}",
- 'zcircle' => "\x{24E9}",
- 'zcircumflex' => "\x{1E91}",
- 'zcurl' => "\x{0291}",
- 'zdot' => "\x{017C}",
- 'zdotbelow' => "\x{1E93}",
- 'zecyrillic' => "\x{0437}",
- 'zedescendercyrillic' => "\x{0499}",
- 'zedieresiscyrillic' => "\x{04DF}",
- 'zehiragana' => "\x{305C}",
- 'zekatakana' => "\x{30BC}",
- 'zeroarabic' => "\x{0660}",
- 'zerobengali' => "\x{09E6}",
- 'zerodeva' => "\x{0966}",
- 'zerogujarati' => "\x{0AE6}",
- 'zerogurmukhi' => "\x{0A66}",
- 'zerohackarabic' => "\x{0660}",
- 'zeroinferior' => "\x{2080}",
- 'zeromonospace' => "\x{FF10}",
- 'zerooldstyle' => "\x{F730}",
- 'zeropersian' => "\x{06F0}",
- 'zerosuperior' => "\x{2070}",
- 'zerothai' => "\x{0E50}",
- 'zerowidthjoiner' => "\x{FEFF}",
- 'zerowidthnonjoiner' => "\x{200C}",
- 'zerowidthspace' => "\x{200B}",
- 'zhbopomofo' => "\x{3113}",
- 'zhearmenian' => "\x{056A}",
- 'zhebrevecyrillic' => "\x{04C2}",
- 'zhecyrillic' => "\x{0436}",
- 'zhedescendercyrillic' => "\x{0497}",
- 'zhedieresiscyrillic' => "\x{04DD}",
- 'zihiragana' => "\x{3058}",
- 'zikatakana' => "\x{30B8}",
- 'zinorhebrew' => "\x{05AE}",
- 'zlinebelow' => "\x{1E95}",
- 'zmonospace' => "\x{FF5A}",
- 'zohiragana' => "\x{305E}",
- 'zokatakana' => "\x{30BE}",
- 'zparen' => "\x{24B5}",
- 'zretroflexhook' => "\x{0290}",
- 'zstroke' => "\x{01B6}",
- 'zuhiragana' => "\x{305A}",
- 'zukatakana' => "\x{30BA}",
- );
-
-# Add to this list the glyphs for new fonts (from aglfn13):
-
-map { $agl{$names{$_}} = pack('U',hex ($_))} (keys %names);
-
-
-# %doubles = (map{$_ => "uni$_"} qw(0394 03A9 0162 2215 00AD 02C9 03BC 2219 00A0 0163));
-
-=head2 lookup ( $usv [, $noAlt [, $noUni] ])
-
-return the Adobe-recommended glyph name for a specific Unicode codepoint (integer). By default
-returns C<uniXXXX> names rather than C<afiiNNNNN> or C<SFnnnnnn> names
-
-If C<$noAlt> is true, C<afii> and C<SF> names are returned rather than C<uniXXXX>.
-
-if C<$noUni> is true, returns undef if it would have to resort to C<uniXXXX> or C<uXXXXXX>
-style names. Essentially this represents a straight lookup in the Adobe-recommended list.
-
-=cut
-
-sub lookup
-{
- my ($num, $noalt, $noUni) = @_;
- my ($val) = sprintf("%04X", $num);
-
- if (defined $names{$val})
- {
- return $names{$val} if ($noalt || $names{$val} !~ m/^(?:afii|SF)/o);
- }
- return undef if $noUni;
- if ($num > 0xFFFF)
- { return "u$val"; }
- elsif ($num)
- { return "uni$val"; }
- else
- { return ".notdef"; }
-}
-
-=head2 parse ( $glyphname )
-
-Parse an Adobe-conformant glyph name, generating a Unicode codepoint sequence equivalent to the glyph (or
-glyph components, should the name represent a ligature). In scalar context, returns a reference to an
-array of Unicodes (decimal). Array is empty if the glyph name is non-conformant.
-In list context, the first item returned is the same array reference as above. The second item
-is a reference to an array containing the extensions (if any) present on the glyph name.
-The '.' that precedes each extension is not included.
-
-=cut
-
-sub parse
-{
- my ($gname, @USVs, @extensions);
- ($gname, @extensions) = split('\.', $_[0]);
- # if name originally started with . (e.g., .null) then $gname will now be '' ... need to fix that up:
- $gname = '.' . shift(@extensions) if $gname eq '';
- if (defined $gname)
- {
- foreach $gname (split('_', $gname))
- {
- if ($gname =~ /^u[0-9a-fA-F]{4,6}$/)
- {
- push @USVs, hex(substr($gname, 1));
- }
- elsif ($gname =~ /^uni([0-9a-fA-F]{4,4})+$/)
- {
- push @USVs, map {hex($_)} ($gname =~ /([0-9a-fA-F]{4,4})/g)
- }
- elsif (exists $agl{$gname})
- {
- push @USVs, unpack ('U*', $agl{$gname});
- }
- }
- }
- return \@USVs unless wantarray;
- my @res = (\@USVs, \@extensions);
- return @res;
-}
-
-#Code used to parse Adobe's agl file and generate text for %agl initialization:
-#while (<ARGV>) {
-# chomp;
-# next if m/^#/;
-# my ($gname, @nums) = split(/[; ]/);
-# if ($#nums > 0 or !defined ($Font::TTF::PSNames::names{$nums[0]}) or $Font::TTF::PSNames::names{$nums[0]} ne $gname)
-# {
-# print "\t'$gname' => \"";
-# map {print "\\x{$_}" } @nums;
-# print "\",\n";
-# }
-# }
-
-=head1 AUTHOR
-
-Martin Hosken Martin_Hosken at sil.org. See L<Font::TTF::Font> for copyright and
-licensing.
-
-=cut
-
-1;
+package Font::TTF::PSNames;
+
+=head1 NAME
+
+Font::TTF::PSNames - Utilities for Postscript glyph name processing
+
+=head1 SYNOPSIS
+
+ use Font::TTF::PSNames qw(parse lookup);
+ $name = lookup($uni);
+ $uni = parse($name);
+
+=head1 METHODS
+
+=cut
+
+use strict;
+use vars qw(%names %agl @EXPORT_OK);
+use Exporter qw( import );
+ at EXPORT_OK = qw( parse lookup);
+
+# Adobe Glyph List for New Fonts
+# from http://partners.adobe.com/asn/tech/type/aglfn13.txt
+
+%names = (
+ '0020' => 'space',
+ '0021' => 'exclam',
+ '0022' => 'quotedbl',
+ '0023' => 'numbersign',
+ '0024' => 'dollar',
+ '0025' => 'percent',
+ '0026' => 'ampersand',
+ '0027' => 'quotesingle',
+ '0028' => 'parenleft',
+ '0029' => 'parenright',
+ '002A' => 'asterisk',
+ '002B' => 'plus',
+ '002C' => 'comma',
+ '002D' => 'hyphen',
+ '002E' => 'period',
+ '002F' => 'slash',
+ '0030' => 'zero',
+ '0031' => 'one',
+ '0032' => 'two',
+ '0033' => 'three',
+ '0034' => 'four',
+ '0035' => 'five',
+ '0036' => 'six',
+ '0037' => 'seven',
+ '0038' => 'eight',
+ '0039' => 'nine',
+ '003A' => 'colon',
+ '003B' => 'semicolon',
+ '003C' => 'less',
+ '003D' => 'equal',
+ '003E' => 'greater',
+ '003F' => 'question',
+ '0040' => 'at',
+ '0041' => 'A',
+ '0042' => 'B',
+ '0043' => 'C',
+ '0044' => 'D',
+ '0045' => 'E',
+ '0046' => 'F',
+ '0047' => 'G',
+ '0048' => 'H',
+ '0049' => 'I',
+ '004A' => 'J',
+ '004B' => 'K',
+ '004C' => 'L',
+ '004D' => 'M',
+ '004E' => 'N',
+ '004F' => 'O',
+ '0050' => 'P',
+ '0051' => 'Q',
+ '0052' => 'R',
+ '0053' => 'S',
+ '0054' => 'T',
+ '0055' => 'U',
+ '0056' => 'V',
+ '0057' => 'W',
+ '0058' => 'X',
+ '0059' => 'Y',
+ '005A' => 'Z',
+ '005B' => 'bracketleft',
+ '005C' => 'backslash',
+ '005D' => 'bracketright',
+ '005E' => 'asciicircum',
+ '005F' => 'underscore',
+ '0060' => 'grave',
+ '0061' => 'a',
+ '0062' => 'b',
+ '0063' => 'c',
+ '0064' => 'd',
+ '0065' => 'e',
+ '0066' => 'f',
+ '0067' => 'g',
+ '0068' => 'h',
+ '0069' => 'i',
+ '006A' => 'j',
+ '006B' => 'k',
+ '006C' => 'l',
+ '006D' => 'm',
+ '006E' => 'n',
+ '006F' => 'o',
+ '0070' => 'p',
+ '0071' => 'q',
+ '0072' => 'r',
+ '0073' => 's',
+ '0074' => 't',
+ '0075' => 'u',
+ '0076' => 'v',
+ '0077' => 'w',
+ '0078' => 'x',
+ '0079' => 'y',
+ '007A' => 'z',
+ '007B' => 'braceleft',
+ '007C' => 'bar',
+ '007D' => 'braceright',
+ '007E' => 'asciitilde',
+# '00A0' => 'space',
+ '00A1' => 'exclamdown',
+ '00A2' => 'cent',
+ '00A3' => 'sterling',
+ '00A4' => 'currency',
+ '00A5' => 'yen',
+ '00A6' => 'brokenbar',
+ '00A7' => 'section',
+ '00A8' => 'dieresis',
+ '00A9' => 'copyright',
+ '00AA' => 'ordfeminine',
+ '00AB' => 'guillemotleft',
+ '00AC' => 'logicalnot',
+# '00AD' => 'hyphen',
+ '00AE' => 'registered',
+ '00AF' => 'macron',
+ '00B0' => 'degree',
+ '00B1' => 'plusminus',
+ '00B2' => 'twosuperior',
+ '00B3' => 'threesuperior',
+ '00B4' => 'acute',
+ '00B5' => 'mu',
+ '00B6' => 'paragraph',
+ '00B7' => 'periodcentered',
+ '00B8' => 'cedilla',
+ '00B9' => 'onesuperior',
+ '00BA' => 'ordmasculine',
+ '00BB' => 'guillemotright',
+ '00BC' => 'onequarter',
+ '00BD' => 'onehalf',
+ '00BE' => 'threequarters',
+ '00BF' => 'questiondown',
+ '00C0' => 'Agrave',
+ '00C1' => 'Aacute',
+ '00C2' => 'Acircumflex',
+ '00C3' => 'Atilde',
+ '00C4' => 'Adieresis',
+ '00C5' => 'Aring',
+ '00C6' => 'AE',
+ '00C7' => 'Ccedilla',
+ '00C8' => 'Egrave',
+ '00C9' => 'Eacute',
+ '00CA' => 'Ecircumflex',
+ '00CB' => 'Edieresis',
+ '00CC' => 'Igrave',
+ '00CD' => 'Iacute',
+ '00CE' => 'Icircumflex',
+ '00CF' => 'Idieresis',
+ '00D0' => 'Eth',
+ '00D1' => 'Ntilde',
+ '00D2' => 'Ograve',
+ '00D3' => 'Oacute',
+ '00D4' => 'Ocircumflex',
+ '00D5' => 'Otilde',
+ '00D6' => 'Odieresis',
+ '00D7' => 'multiply',
+ '00D8' => 'Oslash',
+ '00D9' => 'Ugrave',
+ '00DA' => 'Uacute',
+ '00DB' => 'Ucircumflex',
+ '00DC' => 'Udieresis',
+ '00DD' => 'Yacute',
+ '00DE' => 'Thorn',
+ '00DF' => 'germandbls',
+ '00E0' => 'agrave',
+ '00E1' => 'aacute',
+ '00E2' => 'acircumflex',
+ '00E3' => 'atilde',
+ '00E4' => 'adieresis',
+ '00E5' => 'aring',
+ '00E6' => 'ae',
+ '00E7' => 'ccedilla',
+ '00E8' => 'egrave',
+ '00E9' => 'eacute',
+ '00EA' => 'ecircumflex',
+ '00EB' => 'edieresis',
+ '00EC' => 'igrave',
+ '00ED' => 'iacute',
+ '00EE' => 'icircumflex',
+ '00EF' => 'idieresis',
+ '00F0' => 'eth',
+ '00F1' => 'ntilde',
+ '00F2' => 'ograve',
+ '00F3' => 'oacute',
+ '00F4' => 'ocircumflex',
+ '00F5' => 'otilde',
+ '00F6' => 'odieresis',
+ '00F7' => 'divide',
+ '00F8' => 'oslash',
+ '00F9' => 'ugrave',
+ '00FA' => 'uacute',
+ '00FB' => 'ucircumflex',
+ '00FC' => 'udieresis',
+ '00FD' => 'yacute',
+ '00FE' => 'thorn',
+ '00FF' => 'ydieresis',
+ '0100' => 'Amacron',
+ '0101' => 'amacron',
+ '0102' => 'Abreve',
+ '0103' => 'abreve',
+ '0104' => 'Aogonek',
+ '0105' => 'aogonek',
+ '0106' => 'Cacute',
+ '0107' => 'cacute',
+ '0108' => 'Ccircumflex',
+ '0109' => 'ccircumflex',
+ '010A' => 'Cdotaccent',
+ '010B' => 'cdotaccent',
+ '010C' => 'Ccaron',
+ '010D' => 'ccaron',
+ '010E' => 'Dcaron',
+ '010F' => 'dcaron',
+ '0110' => 'Dcroat',
+ '0111' => 'dcroat',
+ '0112' => 'Emacron',
+ '0113' => 'emacron',
+ '0114' => 'Ebreve',
+ '0115' => 'ebreve',
+ '0116' => 'Edotaccent',
+ '0117' => 'edotaccent',
+ '0118' => 'Eogonek',
+ '0119' => 'eogonek',
+ '011A' => 'Ecaron',
+ '011B' => 'ecaron',
+ '011C' => 'Gcircumflex',
+ '011D' => 'gcircumflex',
+ '011E' => 'Gbreve',
+ '011F' => 'gbreve',
+ '0120' => 'Gdotaccent',
+ '0121' => 'gdotaccent',
+ '0122' => 'Gcommaaccent',
+ '0123' => 'gcommaaccent',
+ '0124' => 'Hcircumflex',
+ '0125' => 'hcircumflex',
+ '0126' => 'Hbar',
+ '0127' => 'hbar',
+ '0128' => 'Itilde',
+ '0129' => 'itilde',
+ '012A' => 'Imacron',
+ '012B' => 'imacron',
+ '012C' => 'Ibreve',
+ '012D' => 'ibreve',
+ '012E' => 'Iogonek',
+ '012F' => 'iogonek',
+ '0130' => 'Idotaccent',
+ '0131' => 'dotlessi',
+ '0132' => 'IJ',
+ '0133' => 'ij',
+ '0134' => 'Jcircumflex',
+ '0135' => 'jcircumflex',
+ '0136' => 'Kcommaaccent',
+ '0137' => 'kcommaaccent',
+ '0138' => 'kgreenlandic',
+ '0139' => 'Lacute',
+ '013A' => 'lacute',
+ '013B' => 'Lcommaaccent',
+ '013C' => 'lcommaaccent',
+ '013D' => 'Lcaron',
+ '013E' => 'lcaron',
+ '013F' => 'Ldot',
+ '0140' => 'ldot',
+ '0141' => 'Lslash',
+ '0142' => 'lslash',
+ '0143' => 'Nacute',
+ '0144' => 'nacute',
+ '0145' => 'Ncommaaccent',
+ '0146' => 'ncommaaccent',
+ '0147' => 'Ncaron',
+ '0148' => 'ncaron',
+ '0149' => 'napostrophe',
+ '014A' => 'Eng',
+ '014B' => 'eng',
+ '014C' => 'Omacron',
+ '014D' => 'omacron',
+ '014E' => 'Obreve',
+ '014F' => 'obreve',
+ '0150' => 'Ohungarumlaut',
+ '0151' => 'ohungarumlaut',
+ '0152' => 'OE',
+ '0153' => 'oe',
+ '0154' => 'Racute',
+ '0155' => 'racute',
+ '0156' => 'Rcommaaccent',
+ '0157' => 'rcommaaccent',
+ '0158' => 'Rcaron',
+ '0159' => 'rcaron',
+ '015A' => 'Sacute',
+ '015B' => 'sacute',
+ '015C' => 'Scircumflex',
+ '015D' => 'scircumflex',
+ '015E' => 'Scedilla',
+ '015F' => 'scedilla',
+ '0160' => 'Scaron',
+ '0161' => 'scaron',
+ '0162' => 'Tcommaaccent',
+ '0163' => 'tcommaaccent',
+ '0164' => 'Tcaron',
+ '0165' => 'tcaron',
+ '0166' => 'Tbar',
+ '0167' => 'tbar',
+ '0168' => 'Utilde',
+ '0169' => 'utilde',
+ '016A' => 'Umacron',
+ '016B' => 'umacron',
+ '016C' => 'Ubreve',
+ '016D' => 'ubreve',
+ '016E' => 'Uring',
+ '016F' => 'uring',
+ '0170' => 'Uhungarumlaut',
+ '0171' => 'uhungarumlaut',
+ '0172' => 'Uogonek',
+ '0173' => 'uogonek',
+ '0174' => 'Wcircumflex',
+ '0175' => 'wcircumflex',
+ '0176' => 'Ycircumflex',
+ '0177' => 'ycircumflex',
+ '0178' => 'Ydieresis',
+ '0179' => 'Zacute',
+ '017A' => 'zacute',
+ '017B' => 'Zdotaccent',
+ '017C' => 'zdotaccent',
+ '017D' => 'Zcaron',
+ '017E' => 'zcaron',
+ '017F' => 'longs',
+ '0192' => 'florin',
+ '01A0' => 'Ohorn',
+ '01A1' => 'ohorn',
+ '01AF' => 'Uhorn',
+ '01B0' => 'uhorn',
+ '01E6' => 'Gcaron',
+ '01E7' => 'gcaron',
+ '01FA' => 'Aringacute',
+ '01FB' => 'aringacute',
+ '01FC' => 'AEacute',
+ '01FD' => 'aeacute',
+ '01FE' => 'Oslashacute',
+ '01FF' => 'oslashacute',
+ '0218' => 'Scommaaccent',
+ '0219' => 'scommaaccent',
+# '021A' => 'Tcommaaccent',
+# '021B' => 'tcommaaccent',
+ '02BC' => 'afii57929',
+ '02BD' => 'afii64937',
+ '02C6' => 'circumflex',
+ '02C7' => 'caron',
+# '02C9' => 'macron',
+ '02D8' => 'breve',
+ '02D9' => 'dotaccent',
+ '02DA' => 'ring',
+ '02DB' => 'ogonek',
+ '02DC' => 'tilde',
+ '02DD' => 'hungarumlaut',
+ '0300' => 'gravecomb',
+ '0301' => 'acutecomb',
+ '0303' => 'tildecomb',
+ '0309' => 'hookabovecomb',
+ '0323' => 'dotbelowcomb',
+ '0384' => 'tonos',
+ '0385' => 'dieresistonos',
+ '0386' => 'Alphatonos',
+ '0387' => 'anoteleia',
+ '0388' => 'Epsilontonos',
+ '0389' => 'Etatonos',
+ '038A' => 'Iotatonos',
+ '038C' => 'Omicrontonos',
+ '038E' => 'Upsilontonos',
+ '038F' => 'Omegatonos',
+ '0390' => 'iotadieresistonos',
+ '0391' => 'Alpha',
+ '0392' => 'Beta',
+ '0393' => 'Gamma',
+# '0394' => 'Delta',
+ '0395' => 'Epsilon',
+ '0396' => 'Zeta',
+ '0397' => 'Eta',
+ '0398' => 'Theta',
+ '0399' => 'Iota',
+ '039A' => 'Kappa',
+ '039B' => 'Lambda',
+ '039C' => 'Mu',
+ '039D' => 'Nu',
+ '039E' => 'Xi',
+ '039F' => 'Omicron',
+ '03A0' => 'Pi',
+ '03A1' => 'Rho',
+ '03A3' => 'Sigma',
+ '03A4' => 'Tau',
+ '03A5' => 'Upsilon',
+ '03A6' => 'Phi',
+ '03A7' => 'Chi',
+ '03A8' => 'Psi',
+# '03A9' => 'Omega',
+ '03AA' => 'Iotadieresis',
+ '03AB' => 'Upsilondieresis',
+ '03AC' => 'alphatonos',
+ '03AD' => 'epsilontonos',
+ '03AE' => 'etatonos',
+ '03AF' => 'iotatonos',
+ '03B0' => 'upsilondieresistonos',
+ '03B1' => 'alpha',
+ '03B2' => 'beta',
+ '03B3' => 'gamma',
+ '03B4' => 'delta',
+ '03B5' => 'epsilon',
+ '03B6' => 'zeta',
+ '03B7' => 'eta',
+ '03B8' => 'theta',
+ '03B9' => 'iota',
+ '03BA' => 'kappa',
+ '03BB' => 'lambda',
+# '03BC' => 'mu',
+ '03BD' => 'nu',
+ '03BE' => 'xi',
+ '03BF' => 'omicron',
+ '03C0' => 'pi',
+ '03C1' => 'rho',
+ '03C2' => 'sigma1',
+ '03C3' => 'sigma',
+ '03C4' => 'tau',
+ '03C5' => 'upsilon',
+ '03C6' => 'phi',
+ '03C7' => 'chi',
+ '03C8' => 'psi',
+ '03C9' => 'omega',
+ '03CA' => 'iotadieresis',
+ '03CB' => 'upsilondieresis',
+ '03CC' => 'omicrontonos',
+ '03CD' => 'upsilontonos',
+ '03CE' => 'omegatonos',
+ '03D1' => 'theta1',
+ '03D2' => 'Upsilon1',
+ '03D5' => 'phi1',
+ '03D6' => 'omega1',
+ '0401' => 'afii10023',
+ '0402' => 'afii10051',
+ '0403' => 'afii10052',
+ '0404' => 'afii10053',
+ '0405' => 'afii10054',
+ '0406' => 'afii10055',
+ '0407' => 'afii10056',
+ '0408' => 'afii10057',
+ '0409' => 'afii10058',
+ '040A' => 'afii10059',
+ '040B' => 'afii10060',
+ '040C' => 'afii10061',
+ '040E' => 'afii10062',
+ '040F' => 'afii10145',
+ '0410' => 'afii10017',
+ '0411' => 'afii10018',
+ '0412' => 'afii10019',
+ '0413' => 'afii10020',
+ '0414' => 'afii10021',
+ '0415' => 'afii10022',
+ '0416' => 'afii10024',
+ '0417' => 'afii10025',
+ '0418' => 'afii10026',
+ '0419' => 'afii10027',
+ '041A' => 'afii10028',
+ '041B' => 'afii10029',
+ '041C' => 'afii10030',
+ '041D' => 'afii10031',
+ '041E' => 'afii10032',
+ '041F' => 'afii10033',
+ '0420' => 'afii10034',
+ '0421' => 'afii10035',
+ '0422' => 'afii10036',
+ '0423' => 'afii10037',
+ '0424' => 'afii10038',
+ '0425' => 'afii10039',
+ '0426' => 'afii10040',
+ '0427' => 'afii10041',
+ '0428' => 'afii10042',
+ '0429' => 'afii10043',
+ '042A' => 'afii10044',
+ '042B' => 'afii10045',
+ '042C' => 'afii10046',
+ '042D' => 'afii10047',
+ '042E' => 'afii10048',
+ '042F' => 'afii10049',
+ '0430' => 'afii10065',
+ '0431' => 'afii10066',
+ '0432' => 'afii10067',
+ '0433' => 'afii10068',
+ '0434' => 'afii10069',
+ '0435' => 'afii10070',
+ '0436' => 'afii10072',
+ '0437' => 'afii10073',
+ '0438' => 'afii10074',
+ '0439' => 'afii10075',
+ '043A' => 'afii10076',
+ '043B' => 'afii10077',
+ '043C' => 'afii10078',
+ '043D' => 'afii10079',
+ '043E' => 'afii10080',
+ '043F' => 'afii10081',
+ '0440' => 'afii10082',
+ '0441' => 'afii10083',
+ '0442' => 'afii10084',
+ '0443' => 'afii10085',
+ '0444' => 'afii10086',
+ '0445' => 'afii10087',
+ '0446' => 'afii10088',
+ '0447' => 'afii10089',
+ '0448' => 'afii10090',
+ '0449' => 'afii10091',
+ '044A' => 'afii10092',
+ '044B' => 'afii10093',
+ '044C' => 'afii10094',
+ '044D' => 'afii10095',
+ '044E' => 'afii10096',
+ '044F' => 'afii10097',
+ '0451' => 'afii10071',
+ '0452' => 'afii10099',
+ '0453' => 'afii10100',
+ '0454' => 'afii10101',
+ '0455' => 'afii10102',
+ '0456' => 'afii10103',
+ '0457' => 'afii10104',
+ '0458' => 'afii10105',
+ '0459' => 'afii10106',
+ '045A' => 'afii10107',
+ '045B' => 'afii10108',
+ '045C' => 'afii10109',
+ '045E' => 'afii10110',
+ '045F' => 'afii10193',
+ '0462' => 'afii10146',
+ '0463' => 'afii10194',
+ '0472' => 'afii10147',
+ '0473' => 'afii10195',
+ '0474' => 'afii10148',
+ '0475' => 'afii10196',
+ '0490' => 'afii10050',
+ '0491' => 'afii10098',
+ '04D9' => 'afii10846',
+ '05B0' => 'afii57799',
+ '05B1' => 'afii57801',
+ '05B2' => 'afii57800',
+ '05B3' => 'afii57802',
+ '05B4' => 'afii57793',
+ '05B5' => 'afii57794',
+ '05B6' => 'afii57795',
+ '05B7' => 'afii57798',
+ '05B8' => 'afii57797',
+ '05B9' => 'afii57806',
+ '05BB' => 'afii57796',
+ '05BC' => 'afii57807',
+ '05BD' => 'afii57839',
+ '05BE' => 'afii57645',
+ '05BF' => 'afii57841',
+ '05C0' => 'afii57842',
+ '05C1' => 'afii57804',
+ '05C2' => 'afii57803',
+ '05C3' => 'afii57658',
+ '05D0' => 'afii57664',
+ '05D1' => 'afii57665',
+ '05D2' => 'afii57666',
+ '05D3' => 'afii57667',
+ '05D4' => 'afii57668',
+ '05D5' => 'afii57669',
+ '05D6' => 'afii57670',
+ '05D7' => 'afii57671',
+ '05D8' => 'afii57672',
+ '05D9' => 'afii57673',
+ '05DA' => 'afii57674',
+ '05DB' => 'afii57675',
+ '05DC' => 'afii57676',
+ '05DD' => 'afii57677',
+ '05DE' => 'afii57678',
+ '05DF' => 'afii57679',
+ '05E0' => 'afii57680',
+ '05E1' => 'afii57681',
+ '05E2' => 'afii57682',
+ '05E3' => 'afii57683',
+ '05E4' => 'afii57684',
+ '05E5' => 'afii57685',
+ '05E6' => 'afii57686',
+ '05E7' => 'afii57687',
+ '05E8' => 'afii57688',
+ '05E9' => 'afii57689',
+ '05EA' => 'afii57690',
+ '05F0' => 'afii57716',
+ '05F1' => 'afii57717',
+ '05F2' => 'afii57718',
+ '060C' => 'afii57388',
+ '061B' => 'afii57403',
+ '061F' => 'afii57407',
+ '0621' => 'afii57409',
+ '0622' => 'afii57410',
+ '0623' => 'afii57411',
+ '0624' => 'afii57412',
+ '0625' => 'afii57413',
+ '0626' => 'afii57414',
+ '0627' => 'afii57415',
+ '0628' => 'afii57416',
+ '0629' => 'afii57417',
+ '062A' => 'afii57418',
+ '062B' => 'afii57419',
+ '062C' => 'afii57420',
+ '062D' => 'afii57421',
+ '062E' => 'afii57422',
+ '062F' => 'afii57423',
+ '0630' => 'afii57424',
+ '0631' => 'afii57425',
+ '0632' => 'afii57426',
+ '0633' => 'afii57427',
+ '0634' => 'afii57428',
+ '0635' => 'afii57429',
+ '0636' => 'afii57430',
+ '0637' => 'afii57431',
+ '0638' => 'afii57432',
+ '0639' => 'afii57433',
+ '063A' => 'afii57434',
+ '0640' => 'afii57440',
+ '0641' => 'afii57441',
+ '0642' => 'afii57442',
+ '0643' => 'afii57443',
+ '0644' => 'afii57444',
+ '0645' => 'afii57445',
+ '0646' => 'afii57446',
+ '0647' => 'afii57470',
+ '0648' => 'afii57448',
+ '0649' => 'afii57449',
+ '064A' => 'afii57450',
+ '064B' => 'afii57451',
+ '064C' => 'afii57452',
+ '064D' => 'afii57453',
+ '064E' => 'afii57454',
+ '064F' => 'afii57455',
+ '0650' => 'afii57456',
+ '0651' => 'afii57457',
+ '0652' => 'afii57458',
+ '0660' => 'afii57392',
+ '0661' => 'afii57393',
+ '0662' => 'afii57394',
+ '0663' => 'afii57395',
+ '0664' => 'afii57396',
+ '0665' => 'afii57397',
+ '0666' => 'afii57398',
+ '0667' => 'afii57399',
+ '0668' => 'afii57400',
+ '0669' => 'afii57401',
+ '066A' => 'afii57381',
+ '066D' => 'afii63167',
+ '0679' => 'afii57511',
+ '067E' => 'afii57506',
+ '0686' => 'afii57507',
+ '0688' => 'afii57512',
+ '0691' => 'afii57513',
+ '0698' => 'afii57508',
+ '06A4' => 'afii57505',
+ '06AF' => 'afii57509',
+ '06BA' => 'afii57514',
+ '06D2' => 'afii57519',
+ '06D5' => 'afii57534',
+ '1E80' => 'Wgrave',
+ '1E81' => 'wgrave',
+ '1E82' => 'Wacute',
+ '1E83' => 'wacute',
+ '1E84' => 'Wdieresis',
+ '1E85' => 'wdieresis',
+ '1EF2' => 'Ygrave',
+ '1EF3' => 'ygrave',
+ '200C' => 'afii61664',
+ '200D' => 'afii301',
+ '200E' => 'afii299',
+ '200F' => 'afii300',
+ '2012' => 'figuredash',
+ '2013' => 'endash',
+ '2014' => 'emdash',
+ '2015' => 'afii00208',
+ '2017' => 'underscoredbl',
+ '2018' => 'quoteleft',
+ '2019' => 'quoteright',
+ '201A' => 'quotesinglbase',
+ '201B' => 'quotereversed',
+ '201C' => 'quotedblleft',
+ '201D' => 'quotedblright',
+ '201E' => 'quotedblbase',
+ '2020' => 'dagger',
+ '2021' => 'daggerdbl',
+ '2022' => 'bullet',
+ '2024' => 'onedotenleader',
+ '2025' => 'twodotenleader',
+ '2026' => 'ellipsis',
+ '202C' => 'afii61573',
+ '202D' => 'afii61574',
+ '202E' => 'afii61575',
+ '2030' => 'perthousand',
+ '2032' => 'minute',
+ '2033' => 'second',
+ '2039' => 'guilsinglleft',
+ '203A' => 'guilsinglright',
+ '203C' => 'exclamdbl',
+ '2044' => 'fraction',
+# '2070' => 'zerosuperior',
+# '2074' => 'foursuperior',
+# '2075' => 'fivesuperior',
+# '2076' => 'sixsuperior',
+# '2077' => 'sevensuperior',
+# '2078' => 'eightsuperior',
+# '2079' => 'ninesuperior',
+# '207D' => 'parenleftsuperior',
+# '207E' => 'parenrightsuperior',
+# '207F' => 'nsuperior',
+# '2080' => 'zeroinferior',
+# '2081' => 'oneinferior',
+# '2082' => 'twoinferior',
+# '2083' => 'threeinferior',
+# '2084' => 'fourinferior',
+# '2085' => 'fiveinferior',
+# '2086' => 'sixinferior',
+# '2087' => 'seveninferior',
+# '2088' => 'eightinferior',
+# '2089' => 'nineinferior',
+# '208D' => 'parenleftinferior',
+# '208E' => 'parenrightinferior',
+ '20A1' => 'colonmonetary',
+ '20A3' => 'franc',
+ '20A4' => 'lira',
+ '20A7' => 'peseta',
+ '20AA' => 'afii57636',
+ '20AB' => 'dong',
+ '20AC' => 'Euro',
+ '2105' => 'afii61248',
+ '2111' => 'Ifraktur',
+ '2113' => 'afii61289',
+ '2116' => 'afii61352',
+ '2118' => 'weierstrass',
+ '211C' => 'Rfraktur',
+ '211E' => 'prescription',
+ '2122' => 'trademark',
+ '2126' => 'Omega',
+ '212E' => 'estimated',
+ '2135' => 'aleph',
+ '2153' => 'onethird',
+ '2154' => 'twothirds',
+ '215B' => 'oneeighth',
+ '215C' => 'threeeighths',
+ '215D' => 'fiveeighths',
+ '215E' => 'seveneighths',
+ '2190' => 'arrowleft',
+ '2191' => 'arrowup',
+ '2192' => 'arrowright',
+ '2193' => 'arrowdown',
+ '2194' => 'arrowboth',
+ '2195' => 'arrowupdn',
+ '21A8' => 'arrowupdnbse',
+ '21B5' => 'carriagereturn',
+ '21D0' => 'arrowdblleft',
+ '21D1' => 'arrowdblup',
+ '21D2' => 'arrowdblright',
+ '21D3' => 'arrowdbldown',
+ '21D4' => 'arrowdblboth',
+ '2200' => 'universal',
+ '2202' => 'partialdiff',
+ '2203' => 'existential',
+ '2205' => 'emptyset',
+ '2206' => 'Delta',
+ '2207' => 'gradient',
+ '2208' => 'element',
+ '2209' => 'notelement',
+ '220B' => 'suchthat',
+ '220F' => 'product',
+ '2211' => 'summation',
+ '2212' => 'minus',
+# '2215' => 'fraction',
+ '2217' => 'asteriskmath',
+# '2219' => 'periodcentered',
+ '221A' => 'radical',
+ '221D' => 'proportional',
+ '221E' => 'infinity',
+ '221F' => 'orthogonal',
+ '2220' => 'angle',
+ '2227' => 'logicaland',
+ '2228' => 'logicalor',
+ '2229' => 'intersection',
+ '222A' => 'union',
+ '222B' => 'integral',
+ '2234' => 'therefore',
+ '223C' => 'similar',
+ '2245' => 'congruent',
+ '2248' => 'approxequal',
+ '2260' => 'notequal',
+ '2261' => 'equivalence',
+ '2264' => 'lessequal',
+ '2265' => 'greaterequal',
+ '2282' => 'propersubset',
+ '2283' => 'propersuperset',
+ '2284' => 'notsubset',
+ '2286' => 'reflexsubset',
+ '2287' => 'reflexsuperset',
+ '2295' => 'circleplus',
+ '2297' => 'circlemultiply',
+ '22A5' => 'perpendicular',
+ '22C5' => 'dotmath',
+ '2302' => 'house',
+ '2310' => 'revlogicalnot',
+ '2320' => 'integraltp',
+ '2321' => 'integralbt',
+ '2329' => 'angleleft',
+ '232A' => 'angleright',
+ '2500' => 'SF100000',
+ '2502' => 'SF110000',
+ '250C' => 'SF010000',
+ '2510' => 'SF030000',
+ '2514' => 'SF020000',
+ '2518' => 'SF040000',
+ '251C' => 'SF080000',
+ '2524' => 'SF090000',
+ '252C' => 'SF060000',
+ '2534' => 'SF070000',
+ '253C' => 'SF050000',
+ '2550' => 'SF430000',
+ '2551' => 'SF240000',
+ '2552' => 'SF510000',
+ '2553' => 'SF520000',
+ '2554' => 'SF390000',
+ '2555' => 'SF220000',
+ '2556' => 'SF210000',
+ '2557' => 'SF250000',
+ '2558' => 'SF500000',
+ '2559' => 'SF490000',
+ '255A' => 'SF380000',
+ '255B' => 'SF280000',
+ '255C' => 'SF270000',
+ '255D' => 'SF260000',
+ '255E' => 'SF360000',
+ '255F' => 'SF370000',
+ '2560' => 'SF420000',
+ '2561' => 'SF190000',
+ '2562' => 'SF200000',
+ '2563' => 'SF230000',
+ '2564' => 'SF470000',
+ '2565' => 'SF480000',
+ '2566' => 'SF410000',
+ '2567' => 'SF450000',
+ '2568' => 'SF460000',
+ '2569' => 'SF400000',
+ '256A' => 'SF540000',
+ '256B' => 'SF530000',
+ '256C' => 'SF440000',
+ '2580' => 'upblock',
+ '2584' => 'dnblock',
+ '2588' => 'block',
+ '258C' => 'lfblock',
+ '2590' => 'rtblock',
+ '2591' => 'ltshade',
+ '2592' => 'shade',
+ '2593' => 'dkshade',
+ '25A0' => 'filledbox',
+ '25A1' => 'H22073',
+ '25AA' => 'H18543',
+ '25AB' => 'H18551',
+ '25AC' => 'filledrect',
+ '25B2' => 'triagup',
+ '25BA' => 'triagrt',
+ '25BC' => 'triagdn',
+ '25C4' => 'triaglf',
+ '25CA' => 'lozenge',
+ '25CB' => 'circle',
+ '25CF' => 'H18533',
+ '25D8' => 'invbullet',
+ '25D9' => 'invcircle',
+ '25E6' => 'openbullet',
+ '263A' => 'smileface',
+ '263B' => 'invsmileface',
+ '263C' => 'sun',
+ '2640' => 'female',
+ '2642' => 'male',
+ '2660' => 'spade',
+ '2663' => 'club',
+ '2665' => 'heart',
+ '2666' => 'diamond',
+ '266A' => 'musicalnote',
+ '266B' => 'musicalnotedbl',
+ 'FB00' => 'ff',
+ 'FB01' => 'fi',
+ 'FB02' => 'fl',
+ 'FB03' => 'ffi',
+ 'FB04' => 'ffl',
+ 'FB1F' => 'afii57705',
+ 'FB2A' => 'afii57694',
+ 'FB2B' => 'afii57695',
+ 'FB35' => 'afii57723',
+ 'FB4B' => 'afii57700',
+);
+
+# Adobe Glyph List 2.0 (sans those in glyph list for *new* fonts) -- thus
+# these are all historic names that could occur in fonts
+# from http://partners.adobe.com/asn/tech/type/glyphlist.txt
+
+%agl = (
+ 'AEmacron' => "\x{01E2}",
+ 'AEsmall' => "\x{F7E6}",
+ 'Aacutesmall' => "\x{F7E1}",
+ 'Abreveacute' => "\x{1EAE}",
+ 'Abrevecyrillic' => "\x{04D0}",
+ 'Abrevedotbelow' => "\x{1EB6}",
+ 'Abrevegrave' => "\x{1EB0}",
+ 'Abrevehookabove' => "\x{1EB2}",
+ 'Abrevetilde' => "\x{1EB4}",
+ 'Acaron' => "\x{01CD}",
+ 'Acircle' => "\x{24B6}",
+ 'Acircumflexacute' => "\x{1EA4}",
+ 'Acircumflexdotbelow' => "\x{1EAC}",
+ 'Acircumflexgrave' => "\x{1EA6}",
+ 'Acircumflexhookabove' => "\x{1EA8}",
+ 'Acircumflexsmall' => "\x{F7E2}",
+ 'Acircumflextilde' => "\x{1EAA}",
+ 'Acute' => "\x{F6C9}",
+ 'Acutesmall' => "\x{F7B4}",
+ 'Acyrillic' => "\x{0410}",
+ 'Adblgrave' => "\x{0200}",
+ 'Adieresiscyrillic' => "\x{04D2}",
+ 'Adieresismacron' => "\x{01DE}",
+ 'Adieresissmall' => "\x{F7E4}",
+ 'Adotbelow' => "\x{1EA0}",
+ 'Adotmacron' => "\x{01E0}",
+ 'Agravesmall' => "\x{F7E0}",
+ 'Ahookabove' => "\x{1EA2}",
+ 'Aiecyrillic' => "\x{04D4}",
+ 'Ainvertedbreve' => "\x{0202}",
+ 'Amonospace' => "\x{FF21}",
+ 'Aringbelow' => "\x{1E00}",
+ 'Aringsmall' => "\x{F7E5}",
+ 'Asmall' => "\x{F761}",
+ 'Atildesmall' => "\x{F7E3}",
+ 'Aybarmenian' => "\x{0531}",
+ 'Bcircle' => "\x{24B7}",
+ 'Bdotaccent' => "\x{1E02}",
+ 'Bdotbelow' => "\x{1E04}",
+ 'Becyrillic' => "\x{0411}",
+ 'Benarmenian' => "\x{0532}",
+ 'Bhook' => "\x{0181}",
+ 'Blinebelow' => "\x{1E06}",
+ 'Bmonospace' => "\x{FF22}",
+ 'Brevesmall' => "\x{F6F4}",
+ 'Bsmall' => "\x{F762}",
+ 'Btopbar' => "\x{0182}",
+ 'Caarmenian' => "\x{053E}",
+ 'Caron' => "\x{F6CA}",
+ 'Caronsmall' => "\x{F6F5}",
+ 'Ccedillaacute' => "\x{1E08}",
+ 'Ccedillasmall' => "\x{F7E7}",
+ 'Ccircle' => "\x{24B8}",
+ 'Cdot' => "\x{010A}",
+ 'Cedillasmall' => "\x{F7B8}",
+ 'Chaarmenian' => "\x{0549}",
+ 'Cheabkhasiancyrillic' => "\x{04BC}",
+ 'Checyrillic' => "\x{0427}",
+ 'Chedescenderabkhasiancyrillic' => "\x{04BE}",
+ 'Chedescendercyrillic' => "\x{04B6}",
+ 'Chedieresiscyrillic' => "\x{04F4}",
+ 'Cheharmenian' => "\x{0543}",
+ 'Chekhakassiancyrillic' => "\x{04CB}",
+ 'Cheverticalstrokecyrillic' => "\x{04B8}",
+ 'Chook' => "\x{0187}",
+ 'Circumflexsmall' => "\x{F6F6}",
+ 'Cmonospace' => "\x{FF23}",
+ 'Coarmenian' => "\x{0551}",
+ 'Csmall' => "\x{F763}",
+ 'DZ' => "\x{01F1}",
+ 'DZcaron' => "\x{01C4}",
+ 'Daarmenian' => "\x{0534}",
+ 'Dafrican' => "\x{0189}",
+ 'Dcedilla' => "\x{1E10}",
+ 'Dcircle' => "\x{24B9}",
+ 'Dcircumflexbelow' => "\x{1E12}",
+ 'Ddotaccent' => "\x{1E0A}",
+ 'Ddotbelow' => "\x{1E0C}",
+ 'Decyrillic' => "\x{0414}",
+ 'Deicoptic' => "\x{03EE}",
+ 'Deltagreek' => "\x{0394}",
+ 'Dhook' => "\x{018A}",
+ 'Dieresis' => "\x{F6CB}",
+ 'DieresisAcute' => "\x{F6CC}",
+ 'DieresisGrave' => "\x{F6CD}",
+ 'Dieresissmall' => "\x{F7A8}",
+ 'Digammagreek' => "\x{03DC}",
+ 'Djecyrillic' => "\x{0402}",
+ 'Dlinebelow' => "\x{1E0E}",
+ 'Dmonospace' => "\x{FF24}",
+ 'Dotaccentsmall' => "\x{F6F7}",
+ 'Dslash' => "\x{0110}",
+ 'Dsmall' => "\x{F764}",
+ 'Dtopbar' => "\x{018B}",
+ 'Dz' => "\x{01F2}",
+ 'Dzcaron' => "\x{01C5}",
+ 'Dzeabkhasiancyrillic' => "\x{04E0}",
+ 'Dzecyrillic' => "\x{0405}",
+ 'Dzhecyrillic' => "\x{040F}",
+ 'Eacutesmall' => "\x{F7E9}",
+ 'Ecedillabreve' => "\x{1E1C}",
+ 'Echarmenian' => "\x{0535}",
+ 'Ecircle' => "\x{24BA}",
+ 'Ecircumflexacute' => "\x{1EBE}",
+ 'Ecircumflexbelow' => "\x{1E18}",
+ 'Ecircumflexdotbelow' => "\x{1EC6}",
+ 'Ecircumflexgrave' => "\x{1EC0}",
+ 'Ecircumflexhookabove' => "\x{1EC2}",
+ 'Ecircumflexsmall' => "\x{F7EA}",
+ 'Ecircumflextilde' => "\x{1EC4}",
+ 'Ecyrillic' => "\x{0404}",
+ 'Edblgrave' => "\x{0204}",
+ 'Edieresissmall' => "\x{F7EB}",
+ 'Edot' => "\x{0116}",
+ 'Edotbelow' => "\x{1EB8}",
+ 'Efcyrillic' => "\x{0424}",
+ 'Egravesmall' => "\x{F7E8}",
+ 'Eharmenian' => "\x{0537}",
+ 'Ehookabove' => "\x{1EBA}",
+ 'Eightroman' => "\x{2167}",
+ 'Einvertedbreve' => "\x{0206}",
+ 'Eiotifiedcyrillic' => "\x{0464}",
+ 'Elcyrillic' => "\x{041B}",
+ 'Elevenroman' => "\x{216A}",
+ 'Emacronacute' => "\x{1E16}",
+ 'Emacrongrave' => "\x{1E14}",
+ 'Emcyrillic' => "\x{041C}",
+ 'Emonospace' => "\x{FF25}",
+ 'Encyrillic' => "\x{041D}",
+ 'Endescendercyrillic' => "\x{04A2}",
+ 'Enghecyrillic' => "\x{04A4}",
+ 'Enhookcyrillic' => "\x{04C7}",
+ 'Eopen' => "\x{0190}",
+ 'Ercyrillic' => "\x{0420}",
+ 'Ereversed' => "\x{018E}",
+ 'Ereversedcyrillic' => "\x{042D}",
+ 'Escyrillic' => "\x{0421}",
+ 'Esdescendercyrillic' => "\x{04AA}",
+ 'Esh' => "\x{01A9}",
+ 'Esmall' => "\x{F765}",
+ 'Etarmenian' => "\x{0538}",
+ 'Ethsmall' => "\x{F7F0}",
+ 'Etilde' => "\x{1EBC}",
+ 'Etildebelow' => "\x{1E1A}",
+ 'Ezh' => "\x{01B7}",
+ 'Ezhcaron' => "\x{01EE}",
+ 'Ezhreversed' => "\x{01B8}",
+ 'Fcircle' => "\x{24BB}",
+ 'Fdotaccent' => "\x{1E1E}",
+ 'Feharmenian' => "\x{0556}",
+ 'Feicoptic' => "\x{03E4}",
+ 'Fhook' => "\x{0191}",
+ 'Fitacyrillic' => "\x{0472}",
+ 'Fiveroman' => "\x{2164}",
+ 'Fmonospace' => "\x{FF26}",
+ 'Fourroman' => "\x{2163}",
+ 'Fsmall' => "\x{F766}",
+ 'GBsquare' => "\x{3387}",
+ 'Gacute' => "\x{01F4}",
+ 'Gammaafrican' => "\x{0194}",
+ 'Gangiacoptic' => "\x{03EA}",
+ 'Gcedilla' => "\x{0122}",
+ 'Gcircle' => "\x{24BC}",
+ 'Gdot' => "\x{0120}",
+ 'Gecyrillic' => "\x{0413}",
+ 'Ghadarmenian' => "\x{0542}",
+ 'Ghemiddlehookcyrillic' => "\x{0494}",
+ 'Ghestrokecyrillic' => "\x{0492}",
+ 'Gheupturncyrillic' => "\x{0490}",
+ 'Ghook' => "\x{0193}",
+ 'Gimarmenian' => "\x{0533}",
+ 'Gjecyrillic' => "\x{0403}",
+ 'Gmacron' => "\x{1E20}",
+ 'Gmonospace' => "\x{FF27}",
+ 'Grave' => "\x{F6CE}",
+ 'Gravesmall' => "\x{F760}",
+ 'Gsmall' => "\x{F767}",
+ 'Gsmallhook' => "\x{029B}",
+ 'Gstroke' => "\x{01E4}",
+ 'HPsquare' => "\x{33CB}",
+ 'Haabkhasiancyrillic' => "\x{04A8}",
+ 'Hadescendercyrillic' => "\x{04B2}",
+ 'Hardsigncyrillic' => "\x{042A}",
+ 'Hbrevebelow' => "\x{1E2A}",
+ 'Hcedilla' => "\x{1E28}",
+ 'Hcircle' => "\x{24BD}",
+ 'Hdieresis' => "\x{1E26}",
+ 'Hdotaccent' => "\x{1E22}",
+ 'Hdotbelow' => "\x{1E24}",
+ 'Hmonospace' => "\x{FF28}",
+ 'Hoarmenian' => "\x{0540}",
+ 'Horicoptic' => "\x{03E8}",
+ 'Hsmall' => "\x{F768}",
+ 'Hungarumlaut' => "\x{F6CF}",
+ 'Hungarumlautsmall' => "\x{F6F8}",
+ 'Hzsquare' => "\x{3390}",
+ 'IAcyrillic' => "\x{042F}",
+ 'IUcyrillic' => "\x{042E}",
+ 'Iacutesmall' => "\x{F7ED}",
+ 'Icaron' => "\x{01CF}",
+ 'Icircle' => "\x{24BE}",
+ 'Icircumflexsmall' => "\x{F7EE}",
+ 'Icyrillic' => "\x{0406}",
+ 'Idblgrave' => "\x{0208}",
+ 'Idieresisacute' => "\x{1E2E}",
+ 'Idieresiscyrillic' => "\x{04E4}",
+ 'Idieresissmall' => "\x{F7EF}",
+ 'Idot' => "\x{0130}",
+ 'Idotbelow' => "\x{1ECA}",
+ 'Iebrevecyrillic' => "\x{04D6}",
+ 'Iecyrillic' => "\x{0415}",
+ 'Igravesmall' => "\x{F7EC}",
+ 'Ihookabove' => "\x{1EC8}",
+ 'Iicyrillic' => "\x{0418}",
+ 'Iinvertedbreve' => "\x{020A}",
+ 'Iishortcyrillic' => "\x{0419}",
+ 'Imacroncyrillic' => "\x{04E2}",
+ 'Imonospace' => "\x{FF29}",
+ 'Iniarmenian' => "\x{053B}",
+ 'Iocyrillic' => "\x{0401}",
+ 'Iotaafrican' => "\x{0196}",
+ 'Ismall' => "\x{F769}",
+ 'Istroke' => "\x{0197}",
+ 'Itildebelow' => "\x{1E2C}",
+ 'Izhitsacyrillic' => "\x{0474}",
+ 'Izhitsadblgravecyrillic' => "\x{0476}",
+ 'Jaarmenian' => "\x{0541}",
+ 'Jcircle' => "\x{24BF}",
+ 'Jecyrillic' => "\x{0408}",
+ 'Jheharmenian' => "\x{054B}",
+ 'Jmonospace' => "\x{FF2A}",
+ 'Jsmall' => "\x{F76A}",
+ 'KBsquare' => "\x{3385}",
+ 'KKsquare' => "\x{33CD}",
+ 'Kabashkircyrillic' => "\x{04A0}",
+ 'Kacute' => "\x{1E30}",
+ 'Kacyrillic' => "\x{041A}",
+ 'Kadescendercyrillic' => "\x{049A}",
+ 'Kahookcyrillic' => "\x{04C3}",
+ 'Kastrokecyrillic' => "\x{049E}",
+ 'Kaverticalstrokecyrillic' => "\x{049C}",
+ 'Kcaron' => "\x{01E8}",
+ 'Kcedilla' => "\x{0136}",
+ 'Kcircle' => "\x{24C0}",
+ 'Kdotbelow' => "\x{1E32}",
+ 'Keharmenian' => "\x{0554}",
+ 'Kenarmenian' => "\x{053F}",
+ 'Khacyrillic' => "\x{0425}",
+ 'Kheicoptic' => "\x{03E6}",
+ 'Khook' => "\x{0198}",
+ 'Kjecyrillic' => "\x{040C}",
+ 'Klinebelow' => "\x{1E34}",
+ 'Kmonospace' => "\x{FF2B}",
+ 'Koppacyrillic' => "\x{0480}",
+ 'Koppagreek' => "\x{03DE}",
+ 'Ksicyrillic' => "\x{046E}",
+ 'Ksmall' => "\x{F76B}",
+ 'LJ' => "\x{01C7}",
+ 'LL' => "\x{F6BF}",
+ 'Lcedilla' => "\x{013B}",
+ 'Lcircle' => "\x{24C1}",
+ 'Lcircumflexbelow' => "\x{1E3C}",
+ 'Ldotaccent' => "\x{013F}",
+ 'Ldotbelow' => "\x{1E36}",
+ 'Ldotbelowmacron' => "\x{1E38}",
+ 'Liwnarmenian' => "\x{053C}",
+ 'Lj' => "\x{01C8}",
+ 'Ljecyrillic' => "\x{0409}",
+ 'Llinebelow' => "\x{1E3A}",
+ 'Lmonospace' => "\x{FF2C}",
+ 'Lslashsmall' => "\x{F6F9}",
+ 'Lsmall' => "\x{F76C}",
+ 'MBsquare' => "\x{3386}",
+ 'Macron' => "\x{F6D0}",
+ 'Macronsmall' => "\x{F7AF}",
+ 'Macute' => "\x{1E3E}",
+ 'Mcircle' => "\x{24C2}",
+ 'Mdotaccent' => "\x{1E40}",
+ 'Mdotbelow' => "\x{1E42}",
+ 'Menarmenian' => "\x{0544}",
+ 'Mmonospace' => "\x{FF2D}",
+ 'Msmall' => "\x{F76D}",
+ 'Mturned' => "\x{019C}",
+ 'NJ' => "\x{01CA}",
+ 'Ncedilla' => "\x{0145}",
+ 'Ncircle' => "\x{24C3}",
+ 'Ncircumflexbelow' => "\x{1E4A}",
+ 'Ndotaccent' => "\x{1E44}",
+ 'Ndotbelow' => "\x{1E46}",
+ 'Nhookleft' => "\x{019D}",
+ 'Nineroman' => "\x{2168}",
+ 'Nj' => "\x{01CB}",
+ 'Njecyrillic' => "\x{040A}",
+ 'Nlinebelow' => "\x{1E48}",
+ 'Nmonospace' => "\x{FF2E}",
+ 'Nowarmenian' => "\x{0546}",
+ 'Nsmall' => "\x{F76E}",
+ 'Ntildesmall' => "\x{F7F1}",
+ 'OEsmall' => "\x{F6FA}",
+ 'Oacutesmall' => "\x{F7F3}",
+ 'Obarredcyrillic' => "\x{04E8}",
+ 'Obarreddieresiscyrillic' => "\x{04EA}",
+ 'Ocaron' => "\x{01D1}",
+ 'Ocenteredtilde' => "\x{019F}",
+ 'Ocircle' => "\x{24C4}",
+ 'Ocircumflexacute' => "\x{1ED0}",
+ 'Ocircumflexdotbelow' => "\x{1ED8}",
+ 'Ocircumflexgrave' => "\x{1ED2}",
+ 'Ocircumflexhookabove' => "\x{1ED4}",
+ 'Ocircumflexsmall' => "\x{F7F4}",
+ 'Ocircumflextilde' => "\x{1ED6}",
+ 'Ocyrillic' => "\x{041E}",
+ 'Odblacute' => "\x{0150}",
+ 'Odblgrave' => "\x{020C}",
+ 'Odieresiscyrillic' => "\x{04E6}",
+ 'Odieresissmall' => "\x{F7F6}",
+ 'Odotbelow' => "\x{1ECC}",
+ 'Ogoneksmall' => "\x{F6FB}",
+ 'Ogravesmall' => "\x{F7F2}",
+ 'Oharmenian' => "\x{0555}",
+ 'Ohm' => "\x{2126}",
+ 'Ohookabove' => "\x{1ECE}",
+ 'Ohornacute' => "\x{1EDA}",
+ 'Ohorndotbelow' => "\x{1EE2}",
+ 'Ohorngrave' => "\x{1EDC}",
+ 'Ohornhookabove' => "\x{1EDE}",
+ 'Ohorntilde' => "\x{1EE0}",
+ 'Oi' => "\x{01A2}",
+ 'Oinvertedbreve' => "\x{020E}",
+ 'Omacronacute' => "\x{1E52}",
+ 'Omacrongrave' => "\x{1E50}",
+ 'Omegacyrillic' => "\x{0460}",
+ 'Omegagreek' => "\x{03A9}",
+ 'Omegaroundcyrillic' => "\x{047A}",
+ 'Omegatitlocyrillic' => "\x{047C}",
+ 'Omonospace' => "\x{FF2F}",
+ 'Oneroman' => "\x{2160}",
+ 'Oogonek' => "\x{01EA}",
+ 'Oogonekmacron' => "\x{01EC}",
+ 'Oopen' => "\x{0186}",
+ 'Oslashsmall' => "\x{F7F8}",
+ 'Osmall' => "\x{F76F}",
+ 'Ostrokeacute' => "\x{01FE}",
+ 'Otcyrillic' => "\x{047E}",
+ 'Otildeacute' => "\x{1E4C}",
+ 'Otildedieresis' => "\x{1E4E}",
+ 'Otildesmall' => "\x{F7F5}",
+ 'Pacute' => "\x{1E54}",
+ 'Pcircle' => "\x{24C5}",
+ 'Pdotaccent' => "\x{1E56}",
+ 'Pecyrillic' => "\x{041F}",
+ 'Peharmenian' => "\x{054A}",
+ 'Pemiddlehookcyrillic' => "\x{04A6}",
+ 'Phook' => "\x{01A4}",
+ 'Piwrarmenian' => "\x{0553}",
+ 'Pmonospace' => "\x{FF30}",
+ 'Psicyrillic' => "\x{0470}",
+ 'Psmall' => "\x{F770}",
+ 'Qcircle' => "\x{24C6}",
+ 'Qmonospace' => "\x{FF31}",
+ 'Qsmall' => "\x{F771}",
+ 'Raarmenian' => "\x{054C}",
+ 'Rcedilla' => "\x{0156}",
+ 'Rcircle' => "\x{24C7}",
+ 'Rdblgrave' => "\x{0210}",
+ 'Rdotaccent' => "\x{1E58}",
+ 'Rdotbelow' => "\x{1E5A}",
+ 'Rdotbelowmacron' => "\x{1E5C}",
+ 'Reharmenian' => "\x{0550}",
+ 'Ringsmall' => "\x{F6FC}",
+ 'Rinvertedbreve' => "\x{0212}",
+ 'Rlinebelow' => "\x{1E5E}",
+ 'Rmonospace' => "\x{FF32}",
+ 'Rsmall' => "\x{F772}",
+ 'Rsmallinverted' => "\x{0281}",
+ 'Rsmallinvertedsuperior' => "\x{02B6}",
+ 'Sacutedotaccent' => "\x{1E64}",
+ 'Sampigreek' => "\x{03E0}",
+ 'Scarondotaccent' => "\x{1E66}",
+ 'Scaronsmall' => "\x{F6FD}",
+ 'Schwa' => "\x{018F}",
+ 'Schwacyrillic' => "\x{04D8}",
+ 'Schwadieresiscyrillic' => "\x{04DA}",
+ 'Scircle' => "\x{24C8}",
+ 'Sdotaccent' => "\x{1E60}",
+ 'Sdotbelow' => "\x{1E62}",
+ 'Sdotbelowdotaccent' => "\x{1E68}",
+ 'Seharmenian' => "\x{054D}",
+ 'Sevenroman' => "\x{2166}",
+ 'Shaarmenian' => "\x{0547}",
+ 'Shacyrillic' => "\x{0428}",
+ 'Shchacyrillic' => "\x{0429}",
+ 'Sheicoptic' => "\x{03E2}",
+ 'Shhacyrillic' => "\x{04BA}",
+ 'Shimacoptic' => "\x{03EC}",
+ 'Sixroman' => "\x{2165}",
+ 'Smonospace' => "\x{FF33}",
+ 'Softsigncyrillic' => "\x{042C}",
+ 'Ssmall' => "\x{F773}",
+ 'Stigmagreek' => "\x{03DA}",
+ 'Tcedilla' => "\x{0162}",
+ 'Tcircle' => "\x{24C9}",
+ 'Tcircumflexbelow' => "\x{1E70}",
+ 'Tdotaccent' => "\x{1E6A}",
+ 'Tdotbelow' => "\x{1E6C}",
+ 'Tecyrillic' => "\x{0422}",
+ 'Tedescendercyrillic' => "\x{04AC}",
+ 'Tenroman' => "\x{2169}",
+ 'Tetsecyrillic' => "\x{04B4}",
+ 'Thook' => "\x{01AC}",
+ 'Thornsmall' => "\x{F7FE}",
+ 'Threeroman' => "\x{2162}",
+ 'Tildesmall' => "\x{F6FE}",
+ 'Tiwnarmenian' => "\x{054F}",
+ 'Tlinebelow' => "\x{1E6E}",
+ 'Tmonospace' => "\x{FF34}",
+ 'Toarmenian' => "\x{0539}",
+ 'Tonefive' => "\x{01BC}",
+ 'Tonesix' => "\x{0184}",
+ 'Tonetwo' => "\x{01A7}",
+ 'Tretroflexhook' => "\x{01AE}",
+ 'Tsecyrillic' => "\x{0426}",
+ 'Tshecyrillic' => "\x{040B}",
+ 'Tsmall' => "\x{F774}",
+ 'Twelveroman' => "\x{216B}",
+ 'Tworoman' => "\x{2161}",
+ 'Uacutesmall' => "\x{F7FA}",
+ 'Ucaron' => "\x{01D3}",
+ 'Ucircle' => "\x{24CA}",
+ 'Ucircumflexbelow' => "\x{1E76}",
+ 'Ucircumflexsmall' => "\x{F7FB}",
+ 'Ucyrillic' => "\x{0423}",
+ 'Udblacute' => "\x{0170}",
+ 'Udblgrave' => "\x{0214}",
+ 'Udieresisacute' => "\x{01D7}",
+ 'Udieresisbelow' => "\x{1E72}",
+ 'Udieresiscaron' => "\x{01D9}",
+ 'Udieresiscyrillic' => "\x{04F0}",
+ 'Udieresisgrave' => "\x{01DB}",
+ 'Udieresismacron' => "\x{01D5}",
+ 'Udieresissmall' => "\x{F7FC}",
+ 'Udotbelow' => "\x{1EE4}",
+ 'Ugravesmall' => "\x{F7F9}",
+ 'Uhookabove' => "\x{1EE6}",
+ 'Uhornacute' => "\x{1EE8}",
+ 'Uhorndotbelow' => "\x{1EF0}",
+ 'Uhorngrave' => "\x{1EEA}",
+ 'Uhornhookabove' => "\x{1EEC}",
+ 'Uhorntilde' => "\x{1EEE}",
+ 'Uhungarumlautcyrillic' => "\x{04F2}",
+ 'Uinvertedbreve' => "\x{0216}",
+ 'Ukcyrillic' => "\x{0478}",
+ 'Umacroncyrillic' => "\x{04EE}",
+ 'Umacrondieresis' => "\x{1E7A}",
+ 'Umonospace' => "\x{FF35}",
+ 'Upsilonacutehooksymbolgreek' => "\x{03D3}",
+ 'Upsilonafrican' => "\x{01B1}",
+ 'Upsilondieresishooksymbolgreek' => "\x{03D4}",
+ 'Upsilonhooksymbol' => "\x{03D2}",
+ 'Ushortcyrillic' => "\x{040E}",
+ 'Usmall' => "\x{F775}",
+ 'Ustraightcyrillic' => "\x{04AE}",
+ 'Ustraightstrokecyrillic' => "\x{04B0}",
+ 'Utildeacute' => "\x{1E78}",
+ 'Utildebelow' => "\x{1E74}",
+ 'Vcircle' => "\x{24CB}",
+ 'Vdotbelow' => "\x{1E7E}",
+ 'Vecyrillic' => "\x{0412}",
+ 'Vewarmenian' => "\x{054E}",
+ 'Vhook' => "\x{01B2}",
+ 'Vmonospace' => "\x{FF36}",
+ 'Voarmenian' => "\x{0548}",
+ 'Vsmall' => "\x{F776}",
+ 'Vtilde' => "\x{1E7C}",
+ 'Wcircle' => "\x{24CC}",
+ 'Wdotaccent' => "\x{1E86}",
+ 'Wdotbelow' => "\x{1E88}",
+ 'Wmonospace' => "\x{FF37}",
+ 'Wsmall' => "\x{F777}",
+ 'Xcircle' => "\x{24CD}",
+ 'Xdieresis' => "\x{1E8C}",
+ 'Xdotaccent' => "\x{1E8A}",
+ 'Xeharmenian' => "\x{053D}",
+ 'Xmonospace' => "\x{FF38}",
+ 'Xsmall' => "\x{F778}",
+ 'Yacutesmall' => "\x{F7FD}",
+ 'Yatcyrillic' => "\x{0462}",
+ 'Ycircle' => "\x{24CE}",
+ 'Ydieresissmall' => "\x{F7FF}",
+ 'Ydotaccent' => "\x{1E8E}",
+ 'Ydotbelow' => "\x{1EF4}",
+ 'Yericyrillic' => "\x{042B}",
+ 'Yerudieresiscyrillic' => "\x{04F8}",
+ 'Yhook' => "\x{01B3}",
+ 'Yhookabove' => "\x{1EF6}",
+ 'Yiarmenian' => "\x{0545}",
+ 'Yicyrillic' => "\x{0407}",
+ 'Yiwnarmenian' => "\x{0552}",
+ 'Ymonospace' => "\x{FF39}",
+ 'Ysmall' => "\x{F779}",
+ 'Ytilde' => "\x{1EF8}",
+ 'Yusbigcyrillic' => "\x{046A}",
+ 'Yusbigiotifiedcyrillic' => "\x{046C}",
+ 'Yuslittlecyrillic' => "\x{0466}",
+ 'Yuslittleiotifiedcyrillic' => "\x{0468}",
+ 'Zaarmenian' => "\x{0536}",
+ 'Zcaronsmall' => "\x{F6FF}",
+ 'Zcircle' => "\x{24CF}",
+ 'Zcircumflex' => "\x{1E90}",
+ 'Zdot' => "\x{017B}",
+ 'Zdotbelow' => "\x{1E92}",
+ 'Zecyrillic' => "\x{0417}",
+ 'Zedescendercyrillic' => "\x{0498}",
+ 'Zedieresiscyrillic' => "\x{04DE}",
+ 'Zhearmenian' => "\x{053A}",
+ 'Zhebrevecyrillic' => "\x{04C1}",
+ 'Zhecyrillic' => "\x{0416}",
+ 'Zhedescendercyrillic' => "\x{0496}",
+ 'Zhedieresiscyrillic' => "\x{04DC}",
+ 'Zlinebelow' => "\x{1E94}",
+ 'Zmonospace' => "\x{FF3A}",
+ 'Zsmall' => "\x{F77A}",
+ 'Zstroke' => "\x{01B5}",
+ 'aabengali' => "\x{0986}",
+ 'aadeva' => "\x{0906}",
+ 'aagujarati' => "\x{0A86}",
+ 'aagurmukhi' => "\x{0A06}",
+ 'aamatragurmukhi' => "\x{0A3E}",
+ 'aarusquare' => "\x{3303}",
+ 'aavowelsignbengali' => "\x{09BE}",
+ 'aavowelsigndeva' => "\x{093E}",
+ 'aavowelsigngujarati' => "\x{0ABE}",
+ 'abbreviationmarkarmenian' => "\x{055F}",
+ 'abbreviationsigndeva' => "\x{0970}",
+ 'abengali' => "\x{0985}",
+ 'abopomofo' => "\x{311A}",
+ 'abreveacute' => "\x{1EAF}",
+ 'abrevecyrillic' => "\x{04D1}",
+ 'abrevedotbelow' => "\x{1EB7}",
+ 'abrevegrave' => "\x{1EB1}",
+ 'abrevehookabove' => "\x{1EB3}",
+ 'abrevetilde' => "\x{1EB5}",
+ 'acaron' => "\x{01CE}",
+ 'acircle' => "\x{24D0}",
+ 'acircumflexacute' => "\x{1EA5}",
+ 'acircumflexdotbelow' => "\x{1EAD}",
+ 'acircumflexgrave' => "\x{1EA7}",
+ 'acircumflexhookabove' => "\x{1EA9}",
+ 'acircumflextilde' => "\x{1EAB}",
+ 'acutebelowcmb' => "\x{0317}",
+ 'acutecmb' => "\x{0301}",
+ 'acutedeva' => "\x{0954}",
+ 'acutelowmod' => "\x{02CF}",
+ 'acutetonecmb' => "\x{0341}",
+ 'acyrillic' => "\x{0430}",
+ 'adblgrave' => "\x{0201}",
+ 'addakgurmukhi' => "\x{0A71}",
+ 'adeva' => "\x{0905}",
+ 'adieresiscyrillic' => "\x{04D3}",
+ 'adieresismacron' => "\x{01DF}",
+ 'adotbelow' => "\x{1EA1}",
+ 'adotmacron' => "\x{01E1}",
+ 'aekorean' => "\x{3150}",
+ 'aemacron' => "\x{01E3}",
+ 'afii08941' => "\x{20A4}",
+ 'afii10063' => "\x{F6C4}",
+ 'afii10064' => "\x{F6C5}",
+ 'afii10192' => "\x{F6C6}",
+ 'afii10831' => "\x{F6C7}",
+ 'afii10832' => "\x{F6C8}",
+ 'agujarati' => "\x{0A85}",
+ 'agurmukhi' => "\x{0A05}",
+ 'ahiragana' => "\x{3042}",
+ 'ahookabove' => "\x{1EA3}",
+ 'aibengali' => "\x{0990}",
+ 'aibopomofo' => "\x{311E}",
+ 'aideva' => "\x{0910}",
+ 'aiecyrillic' => "\x{04D5}",
+ 'aigujarati' => "\x{0A90}",
+ 'aigurmukhi' => "\x{0A10}",
+ 'aimatragurmukhi' => "\x{0A48}",
+ 'ainarabic' => "\x{0639}",
+ 'ainfinalarabic' => "\x{FECA}",
+ 'aininitialarabic' => "\x{FECB}",
+ 'ainmedialarabic' => "\x{FECC}",
+ 'ainvertedbreve' => "\x{0203}",
+ 'aivowelsignbengali' => "\x{09C8}",
+ 'aivowelsigndeva' => "\x{0948}",
+ 'aivowelsigngujarati' => "\x{0AC8}",
+ 'akatakana' => "\x{30A2}",
+ 'akatakanahalfwidth' => "\x{FF71}",
+ 'akorean' => "\x{314F}",
+ 'alef' => "\x{05D0}",
+ 'alefarabic' => "\x{0627}",
+ 'alefdageshhebrew' => "\x{FB30}",
+ 'aleffinalarabic' => "\x{FE8E}",
+ 'alefhamzaabovearabic' => "\x{0623}",
+ 'alefhamzaabovefinalarabic' => "\x{FE84}",
+ 'alefhamzabelowarabic' => "\x{0625}",
+ 'alefhamzabelowfinalarabic' => "\x{FE88}",
+ 'alefhebrew' => "\x{05D0}",
+ 'aleflamedhebrew' => "\x{FB4F}",
+ 'alefmaddaabovearabic' => "\x{0622}",
+ 'alefmaddaabovefinalarabic' => "\x{FE82}",
+ 'alefmaksuraarabic' => "\x{0649}",
+ 'alefmaksurafinalarabic' => "\x{FEF0}",
+ 'alefmaksurainitialarabic' => "\x{FEF3}",
+ 'alefmaksuramedialarabic' => "\x{FEF4}",
+ 'alefpatahhebrew' => "\x{FB2E}",
+ 'alefqamatshebrew' => "\x{FB2F}",
+ 'allequal' => "\x{224C}",
+ 'amonospace' => "\x{FF41}",
+ 'ampersandmonospace' => "\x{FF06}",
+ 'ampersandsmall' => "\x{F726}",
+ 'amsquare' => "\x{33C2}",
+ 'anbopomofo' => "\x{3122}",
+ 'angbopomofo' => "\x{3124}",
+ 'angkhankhuthai' => "\x{0E5A}",
+ 'anglebracketleft' => "\x{3008}",
+ 'anglebracketleftvertical' => "\x{FE3F}",
+ 'anglebracketright' => "\x{3009}",
+ 'anglebracketrightvertical' => "\x{FE40}",
+ 'angstrom' => "\x{212B}",
+ 'anudattadeva' => "\x{0952}",
+ 'anusvarabengali' => "\x{0982}",
+ 'anusvaradeva' => "\x{0902}",
+ 'anusvaragujarati' => "\x{0A82}",
+ 'apaatosquare' => "\x{3300}",
+ 'aparen' => "\x{249C}",
+ 'apostrophearmenian' => "\x{055A}",
+ 'apostrophemod' => "\x{02BC}",
+ 'apple' => "\x{F8FF}",
+ 'approaches' => "\x{2250}",
+ 'approxequalorimage' => "\x{2252}",
+ 'approximatelyequal' => "\x{2245}",
+ 'araeaekorean' => "\x{318E}",
+ 'araeakorean' => "\x{318D}",
+ 'arc' => "\x{2312}",
+ 'arighthalfring' => "\x{1E9A}",
+ 'aringbelow' => "\x{1E01}",
+ 'arrowdashdown' => "\x{21E3}",
+ 'arrowdashleft' => "\x{21E0}",
+ 'arrowdashright' => "\x{21E2}",
+ 'arrowdashup' => "\x{21E1}",
+ 'arrowdownleft' => "\x{2199}",
+ 'arrowdownright' => "\x{2198}",
+ 'arrowdownwhite' => "\x{21E9}",
+ 'arrowheaddownmod' => "\x{02C5}",
+ 'arrowheadleftmod' => "\x{02C2}",
+ 'arrowheadrightmod' => "\x{02C3}",
+ 'arrowheadupmod' => "\x{02C4}",
+ 'arrowhorizex' => "\x{F8E7}",
+ 'arrowleftdbl' => "\x{21D0}",
+ 'arrowleftdblstroke' => "\x{21CD}",
+ 'arrowleftoverright' => "\x{21C6}",
+ 'arrowleftwhite' => "\x{21E6}",
+ 'arrowrightdblstroke' => "\x{21CF}",
+ 'arrowrightheavy' => "\x{279E}",
+ 'arrowrightoverleft' => "\x{21C4}",
+ 'arrowrightwhite' => "\x{21E8}",
+ 'arrowtableft' => "\x{21E4}",
+ 'arrowtabright' => "\x{21E5}",
+ 'arrowupdownbase' => "\x{21A8}",
+ 'arrowupleft' => "\x{2196}",
+ 'arrowupleftofdown' => "\x{21C5}",
+ 'arrowupright' => "\x{2197}",
+ 'arrowupwhite' => "\x{21E7}",
+ 'arrowvertex' => "\x{F8E6}",
+ 'asciicircummonospace' => "\x{FF3E}",
+ 'asciitildemonospace' => "\x{FF5E}",
+ 'ascript' => "\x{0251}",
+ 'ascriptturned' => "\x{0252}",
+ 'asmallhiragana' => "\x{3041}",
+ 'asmallkatakana' => "\x{30A1}",
+ 'asmallkatakanahalfwidth' => "\x{FF67}",
+ 'asteriskaltonearabic' => "\x{066D}",
+ 'asteriskarabic' => "\x{066D}",
+ 'asteriskmonospace' => "\x{FF0A}",
+ 'asterisksmall' => "\x{FE61}",
+ 'asterism' => "\x{2042}",
+ 'asuperior' => "\x{F6E9}",
+ 'asymptoticallyequal' => "\x{2243}",
+ 'atmonospace' => "\x{FF20}",
+ 'atsmall' => "\x{FE6B}",
+ 'aturned' => "\x{0250}",
+ 'aubengali' => "\x{0994}",
+ 'aubopomofo' => "\x{3120}",
+ 'audeva' => "\x{0914}",
+ 'augujarati' => "\x{0A94}",
+ 'augurmukhi' => "\x{0A14}",
+ 'aulengthmarkbengali' => "\x{09D7}",
+ 'aumatragurmukhi' => "\x{0A4C}",
+ 'auvowelsignbengali' => "\x{09CC}",
+ 'auvowelsigndeva' => "\x{094C}",
+ 'auvowelsigngujarati' => "\x{0ACC}",
+ 'avagrahadeva' => "\x{093D}",
+ 'aybarmenian' => "\x{0561}",
+ 'ayin' => "\x{05E2}",
+ 'ayinaltonehebrew' => "\x{FB20}",
+ 'ayinhebrew' => "\x{05E2}",
+ 'babengali' => "\x{09AC}",
+ 'backslashmonospace' => "\x{FF3C}",
+ 'badeva' => "\x{092C}",
+ 'bagujarati' => "\x{0AAC}",
+ 'bagurmukhi' => "\x{0A2C}",
+ 'bahiragana' => "\x{3070}",
+ 'bahtthai' => "\x{0E3F}",
+ 'bakatakana' => "\x{30D0}",
+ 'barmonospace' => "\x{FF5C}",
+ 'bbopomofo' => "\x{3105}",
+ 'bcircle' => "\x{24D1}",
+ 'bdotaccent' => "\x{1E03}",
+ 'bdotbelow' => "\x{1E05}",
+ 'beamedsixteenthnotes' => "\x{266C}",
+ 'because' => "\x{2235}",
+ 'becyrillic' => "\x{0431}",
+ 'beharabic' => "\x{0628}",
+ 'behfinalarabic' => "\x{FE90}",
+ 'behinitialarabic' => "\x{FE91}",
+ 'behiragana' => "\x{3079}",
+ 'behmedialarabic' => "\x{FE92}",
+ 'behmeeminitialarabic' => "\x{FC9F}",
+ 'behmeemisolatedarabic' => "\x{FC08}",
+ 'behnoonfinalarabic' => "\x{FC6D}",
+ 'bekatakana' => "\x{30D9}",
+ 'benarmenian' => "\x{0562}",
+ 'bet' => "\x{05D1}",
+ 'betasymbolgreek' => "\x{03D0}",
+ 'betdagesh' => "\x{FB31}",
+ 'betdageshhebrew' => "\x{FB31}",
+ 'bethebrew' => "\x{05D1}",
+ 'betrafehebrew' => "\x{FB4C}",
+ 'bhabengali' => "\x{09AD}",
+ 'bhadeva' => "\x{092D}",
+ 'bhagujarati' => "\x{0AAD}",
+ 'bhagurmukhi' => "\x{0A2D}",
+ 'bhook' => "\x{0253}",
+ 'bihiragana' => "\x{3073}",
+ 'bikatakana' => "\x{30D3}",
+ 'bilabialclick' => "\x{0298}",
+ 'bindigurmukhi' => "\x{0A02}",
+ 'birusquare' => "\x{3331}",
+ 'blackcircle' => "\x{25CF}",
+ 'blackdiamond' => "\x{25C6}",
+ 'blackdownpointingtriangle' => "\x{25BC}",
+ 'blackleftpointingpointer' => "\x{25C4}",
+ 'blackleftpointingtriangle' => "\x{25C0}",
+ 'blacklenticularbracketleft' => "\x{3010}",
+ 'blacklenticularbracketleftvertical' => "\x{FE3B}",
+ 'blacklenticularbracketright' => "\x{3011}",
+ 'blacklenticularbracketrightvertical' => "\x{FE3C}",
+ 'blacklowerlefttriangle' => "\x{25E3}",
+ 'blacklowerrighttriangle' => "\x{25E2}",
+ 'blackrectangle' => "\x{25AC}",
+ 'blackrightpointingpointer' => "\x{25BA}",
+ 'blackrightpointingtriangle' => "\x{25B6}",
+ 'blacksmallsquare' => "\x{25AA}",
+ 'blacksmilingface' => "\x{263B}",
+ 'blacksquare' => "\x{25A0}",
+ 'blackstar' => "\x{2605}",
+ 'blackupperlefttriangle' => "\x{25E4}",
+ 'blackupperrighttriangle' => "\x{25E5}",
+ 'blackuppointingsmalltriangle' => "\x{25B4}",
+ 'blackuppointingtriangle' => "\x{25B2}",
+ 'blank' => "\x{2423}",
+ 'blinebelow' => "\x{1E07}",
+ 'bmonospace' => "\x{FF42}",
+ 'bobaimaithai' => "\x{0E1A}",
+ 'bohiragana' => "\x{307C}",
+ 'bokatakana' => "\x{30DC}",
+ 'bparen' => "\x{249D}",
+ 'bqsquare' => "\x{33C3}",
+ 'braceex' => "\x{F8F4}",
+ 'braceleftbt' => "\x{F8F3}",
+ 'braceleftmid' => "\x{F8F2}",
+ 'braceleftmonospace' => "\x{FF5B}",
+ 'braceleftsmall' => "\x{FE5B}",
+ 'bracelefttp' => "\x{F8F1}",
+ 'braceleftvertical' => "\x{FE37}",
+ 'bracerightbt' => "\x{F8FE}",
+ 'bracerightmid' => "\x{F8FD}",
+ 'bracerightmonospace' => "\x{FF5D}",
+ 'bracerightsmall' => "\x{FE5C}",
+ 'bracerighttp' => "\x{F8FC}",
+ 'bracerightvertical' => "\x{FE38}",
+ 'bracketleftbt' => "\x{F8F0}",
+ 'bracketleftex' => "\x{F8EF}",
+ 'bracketleftmonospace' => "\x{FF3B}",
+ 'bracketlefttp' => "\x{F8EE}",
+ 'bracketrightbt' => "\x{F8FB}",
+ 'bracketrightex' => "\x{F8FA}",
+ 'bracketrightmonospace' => "\x{FF3D}",
+ 'bracketrighttp' => "\x{F8F9}",
+ 'brevebelowcmb' => "\x{032E}",
+ 'brevecmb' => "\x{0306}",
+ 'breveinvertedbelowcmb' => "\x{032F}",
+ 'breveinvertedcmb' => "\x{0311}",
+ 'breveinverteddoublecmb' => "\x{0361}",
+ 'bridgebelowcmb' => "\x{032A}",
+ 'bridgeinvertedbelowcmb' => "\x{033A}",
+ 'bstroke' => "\x{0180}",
+ 'bsuperior' => "\x{F6EA}",
+ 'btopbar' => "\x{0183}",
+ 'buhiragana' => "\x{3076}",
+ 'bukatakana' => "\x{30D6}",
+ 'bulletinverse' => "\x{25D8}",
+ 'bulletoperator' => "\x{2219}",
+ 'bullseye' => "\x{25CE}",
+ 'caarmenian' => "\x{056E}",
+ 'cabengali' => "\x{099A}",
+ 'cadeva' => "\x{091A}",
+ 'cagujarati' => "\x{0A9A}",
+ 'cagurmukhi' => "\x{0A1A}",
+ 'calsquare' => "\x{3388}",
+ 'candrabindubengali' => "\x{0981}",
+ 'candrabinducmb' => "\x{0310}",
+ 'candrabindudeva' => "\x{0901}",
+ 'candrabindugujarati' => "\x{0A81}",
+ 'capslock' => "\x{21EA}",
+ 'careof' => "\x{2105}",
+ 'caronbelowcmb' => "\x{032C}",
+ 'caroncmb' => "\x{030C}",
+ 'cbopomofo' => "\x{3118}",
+ 'ccedillaacute' => "\x{1E09}",
+ 'ccircle' => "\x{24D2}",
+ 'ccurl' => "\x{0255}",
+ 'cdot' => "\x{010B}",
+ 'cdsquare' => "\x{33C5}",
+ 'cedillacmb' => "\x{0327}",
+ 'centigrade' => "\x{2103}",
+ 'centinferior' => "\x{F6DF}",
+ 'centmonospace' => "\x{FFE0}",
+ 'centoldstyle' => "\x{F7A2}",
+ 'centsuperior' => "\x{F6E0}",
+ 'chaarmenian' => "\x{0579}",
+ 'chabengali' => "\x{099B}",
+ 'chadeva' => "\x{091B}",
+ 'chagujarati' => "\x{0A9B}",
+ 'chagurmukhi' => "\x{0A1B}",
+ 'chbopomofo' => "\x{3114}",
+ 'cheabkhasiancyrillic' => "\x{04BD}",
+ 'checkmark' => "\x{2713}",
+ 'checyrillic' => "\x{0447}",
+ 'chedescenderabkhasiancyrillic' => "\x{04BF}",
+ 'chedescendercyrillic' => "\x{04B7}",
+ 'chedieresiscyrillic' => "\x{04F5}",
+ 'cheharmenian' => "\x{0573}",
+ 'chekhakassiancyrillic' => "\x{04CC}",
+ 'cheverticalstrokecyrillic' => "\x{04B9}",
+ 'chieuchacirclekorean' => "\x{3277}",
+ 'chieuchaparenkorean' => "\x{3217}",
+ 'chieuchcirclekorean' => "\x{3269}",
+ 'chieuchkorean' => "\x{314A}",
+ 'chieuchparenkorean' => "\x{3209}",
+ 'chochangthai' => "\x{0E0A}",
+ 'chochanthai' => "\x{0E08}",
+ 'chochingthai' => "\x{0E09}",
+ 'chochoethai' => "\x{0E0C}",
+ 'chook' => "\x{0188}",
+ 'cieucacirclekorean' => "\x{3276}",
+ 'cieucaparenkorean' => "\x{3216}",
+ 'cieuccirclekorean' => "\x{3268}",
+ 'cieuckorean' => "\x{3148}",
+ 'cieucparenkorean' => "\x{3208}",
+ 'cieucuparenkorean' => "\x{321C}",
+ 'circleot' => "\x{2299}",
+ 'circlepostalmark' => "\x{3036}",
+ 'circlewithlefthalfblack' => "\x{25D0}",
+ 'circlewithrighthalfblack' => "\x{25D1}",
+ 'circumflexbelowcmb' => "\x{032D}",
+ 'circumflexcmb' => "\x{0302}",
+ 'clear' => "\x{2327}",
+ 'clickalveolar' => "\x{01C2}",
+ 'clickdental' => "\x{01C0}",
+ 'clicklateral' => "\x{01C1}",
+ 'clickretroflex' => "\x{01C3}",
+ 'clubsuitblack' => "\x{2663}",
+ 'clubsuitwhite' => "\x{2667}",
+ 'cmcubedsquare' => "\x{33A4}",
+ 'cmonospace' => "\x{FF43}",
+ 'cmsquaredsquare' => "\x{33A0}",
+ 'coarmenian' => "\x{0581}",
+ 'colonmonospace' => "\x{FF1A}",
+ 'colonsign' => "\x{20A1}",
+ 'colonsmall' => "\x{FE55}",
+ 'colontriangularhalfmod' => "\x{02D1}",
+ 'colontriangularmod' => "\x{02D0}",
+ 'commaabovecmb' => "\x{0313}",
+ 'commaaboverightcmb' => "\x{0315}",
+ 'commaaccent' => "\x{F6C3}",
+ 'commaarabic' => "\x{060C}",
+ 'commaarmenian' => "\x{055D}",
+ 'commainferior' => "\x{F6E1}",
+ 'commamonospace' => "\x{FF0C}",
+ 'commareversedabovecmb' => "\x{0314}",
+ 'commareversedmod' => "\x{02BD}",
+ 'commasmall' => "\x{FE50}",
+ 'commasuperior' => "\x{F6E2}",
+ 'commaturnedabovecmb' => "\x{0312}",
+ 'commaturnedmod' => "\x{02BB}",
+ 'compass' => "\x{263C}",
+ 'contourintegral' => "\x{222E}",
+ 'control' => "\x{2303}",
+ 'controlACK' => "\x{0006}",
+ 'controlBEL' => "\x{0007}",
+ 'controlBS' => "\x{0008}",
+ 'controlCAN' => "\x{0018}",
+ 'controlCR' => "\x{000D}",
+ 'controlDC1' => "\x{0011}",
+ 'controlDC2' => "\x{0012}",
+ 'controlDC3' => "\x{0013}",
+ 'controlDC4' => "\x{0014}",
+ 'controlDEL' => "\x{007F}",
+ 'controlDLE' => "\x{0010}",
+ 'controlEM' => "\x{0019}",
+ 'controlENQ' => "\x{0005}",
+ 'controlEOT' => "\x{0004}",
+ 'controlESC' => "\x{001B}",
+ 'controlETB' => "\x{0017}",
+ 'controlETX' => "\x{0003}",
+ 'controlFF' => "\x{000C}",
+ 'controlFS' => "\x{001C}",
+ 'controlGS' => "\x{001D}",
+ 'controlHT' => "\x{0009}",
+ 'controlLF' => "\x{000A}",
+ 'controlNAK' => "\x{0015}",
+ 'controlRS' => "\x{001E}",
+ 'controlSI' => "\x{000F}",
+ 'controlSO' => "\x{000E}",
+ 'controlSOT' => "\x{0002}",
+ 'controlSTX' => "\x{0001}",
+ 'controlSUB' => "\x{001A}",
+ 'controlSYN' => "\x{0016}",
+ 'controlUS' => "\x{001F}",
+ 'controlVT' => "\x{000B}",
+ 'copyrightsans' => "\x{F8E9}",
+ 'copyrightserif' => "\x{F6D9}",
+ 'cornerbracketleft' => "\x{300C}",
+ 'cornerbracketlefthalfwidth' => "\x{FF62}",
+ 'cornerbracketleftvertical' => "\x{FE41}",
+ 'cornerbracketright' => "\x{300D}",
+ 'cornerbracketrighthalfwidth' => "\x{FF63}",
+ 'cornerbracketrightvertical' => "\x{FE42}",
+ 'corporationsquare' => "\x{337F}",
+ 'cosquare' => "\x{33C7}",
+ 'coverkgsquare' => "\x{33C6}",
+ 'cparen' => "\x{249E}",
+ 'cruzeiro' => "\x{20A2}",
+ 'cstretched' => "\x{0297}",
+ 'curlyand' => "\x{22CF}",
+ 'curlyor' => "\x{22CE}",
+ 'cyrBreve' => "\x{F6D1}",
+ 'cyrFlex' => "\x{F6D2}",
+ 'cyrbreve' => "\x{F6D4}",
+ 'cyrflex' => "\x{F6D5}",
+ 'daarmenian' => "\x{0564}",
+ 'dabengali' => "\x{09A6}",
+ 'dadarabic' => "\x{0636}",
+ 'dadeva' => "\x{0926}",
+ 'dadfinalarabic' => "\x{FEBE}",
+ 'dadinitialarabic' => "\x{FEBF}",
+ 'dadmedialarabic' => "\x{FEC0}",
+ 'dagesh' => "\x{05BC}",
+ 'dageshhebrew' => "\x{05BC}",
+ 'dagujarati' => "\x{0AA6}",
+ 'dagurmukhi' => "\x{0A26}",
+ 'dahiragana' => "\x{3060}",
+ 'dakatakana' => "\x{30C0}",
+ 'dalarabic' => "\x{062F}",
+ 'dalet' => "\x{05D3}",
+ 'daletdagesh' => "\x{FB33}",
+ 'daletdageshhebrew' => "\x{FB33}",
+ 'dalethatafpatah' => "\x{05D3}\x{05B2}",
+ 'dalethatafpatahhebrew' => "\x{05D3}\x{05B2}",
+ 'dalethatafsegol' => "\x{05D3}\x{05B1}",
+ 'dalethatafsegolhebrew' => "\x{05D3}\x{05B1}",
+ 'dalethebrew' => "\x{05D3}",
+ 'dalethiriq' => "\x{05D3}\x{05B4}",
+ 'dalethiriqhebrew' => "\x{05D3}\x{05B4}",
+ 'daletholam' => "\x{05D3}\x{05B9}",
+ 'daletholamhebrew' => "\x{05D3}\x{05B9}",
+ 'daletpatah' => "\x{05D3}\x{05B7}",
+ 'daletpatahhebrew' => "\x{05D3}\x{05B7}",
+ 'daletqamats' => "\x{05D3}\x{05B8}",
+ 'daletqamatshebrew' => "\x{05D3}\x{05B8}",
+ 'daletqubuts' => "\x{05D3}\x{05BB}",
+ 'daletqubutshebrew' => "\x{05D3}\x{05BB}",
+ 'daletsegol' => "\x{05D3}\x{05B6}",
+ 'daletsegolhebrew' => "\x{05D3}\x{05B6}",
+ 'daletsheva' => "\x{05D3}\x{05B0}",
+ 'daletshevahebrew' => "\x{05D3}\x{05B0}",
+ 'dalettsere' => "\x{05D3}\x{05B5}",
+ 'dalettserehebrew' => "\x{05D3}\x{05B5}",
+ 'dalfinalarabic' => "\x{FEAA}",
+ 'dammaarabic' => "\x{064F}",
+ 'dammalowarabic' => "\x{064F}",
+ 'dammatanaltonearabic' => "\x{064C}",
+ 'dammatanarabic' => "\x{064C}",
+ 'danda' => "\x{0964}",
+ 'dargahebrew' => "\x{05A7}",
+ 'dargalefthebrew' => "\x{05A7}",
+ 'dasiapneumatacyrilliccmb' => "\x{0485}",
+ 'dblGrave' => "\x{F6D3}",
+ 'dblanglebracketleft' => "\x{300A}",
+ 'dblanglebracketleftvertical' => "\x{FE3D}",
+ 'dblanglebracketright' => "\x{300B}",
+ 'dblanglebracketrightvertical' => "\x{FE3E}",
+ 'dblarchinvertedbelowcmb' => "\x{032B}",
+ 'dblarrowleft' => "\x{21D4}",
+ 'dblarrowright' => "\x{21D2}",
+ 'dbldanda' => "\x{0965}",
+ 'dblgrave' => "\x{F6D6}",
+ 'dblgravecmb' => "\x{030F}",
+ 'dblintegral' => "\x{222C}",
+ 'dbllowline' => "\x{2017}",
+ 'dbllowlinecmb' => "\x{0333}",
+ 'dbloverlinecmb' => "\x{033F}",
+ 'dblprimemod' => "\x{02BA}",
+ 'dblverticalbar' => "\x{2016}",
+ 'dblverticallineabovecmb' => "\x{030E}",
+ 'dbopomofo' => "\x{3109}",
+ 'dbsquare' => "\x{33C8}",
+ 'dcedilla' => "\x{1E11}",
+ 'dcircle' => "\x{24D3}",
+ 'dcircumflexbelow' => "\x{1E13}",
+ 'ddabengali' => "\x{09A1}",
+ 'ddadeva' => "\x{0921}",
+ 'ddagujarati' => "\x{0AA1}",
+ 'ddagurmukhi' => "\x{0A21}",
+ 'ddalarabic' => "\x{0688}",
+ 'ddalfinalarabic' => "\x{FB89}",
+ 'dddhadeva' => "\x{095C}",
+ 'ddhabengali' => "\x{09A2}",
+ 'ddhadeva' => "\x{0922}",
+ 'ddhagujarati' => "\x{0AA2}",
+ 'ddhagurmukhi' => "\x{0A22}",
+ 'ddotaccent' => "\x{1E0B}",
+ 'ddotbelow' => "\x{1E0D}",
+ 'decimalseparatorarabic' => "\x{066B}",
+ 'decimalseparatorpersian' => "\x{066B}",
+ 'decyrillic' => "\x{0434}",
+ 'dehihebrew' => "\x{05AD}",
+ 'dehiragana' => "\x{3067}",
+ 'deicoptic' => "\x{03EF}",
+ 'dekatakana' => "\x{30C7}",
+ 'deleteleft' => "\x{232B}",
+ 'deleteright' => "\x{2326}",
+ 'deltaturned' => "\x{018D}",
+ 'denominatorminusonenumeratorbengali' => "\x{09F8}",
+ 'dezh' => "\x{02A4}",
+ 'dhabengali' => "\x{09A7}",
+ 'dhadeva' => "\x{0927}",
+ 'dhagujarati' => "\x{0AA7}",
+ 'dhagurmukhi' => "\x{0A27}",
+ 'dhook' => "\x{0257}",
+ 'dialytikatonos' => "\x{0385}",
+ 'dialytikatonoscmb' => "\x{0344}",
+ 'diamondsuitwhite' => "\x{2662}",
+ 'dieresisacute' => "\x{F6D7}",
+ 'dieresisbelowcmb' => "\x{0324}",
+ 'dieresiscmb' => "\x{0308}",
+ 'dieresisgrave' => "\x{F6D8}",
+ 'dihiragana' => "\x{3062}",
+ 'dikatakana' => "\x{30C2}",
+ 'dittomark' => "\x{3003}",
+ 'divides' => "\x{2223}",
+ 'divisionslash' => "\x{2215}",
+ 'djecyrillic' => "\x{0452}",
+ 'dlinebelow' => "\x{1E0F}",
+ 'dlsquare' => "\x{3397}",
+ 'dmacron' => "\x{0111}",
+ 'dmonospace' => "\x{FF44}",
+ 'dochadathai' => "\x{0E0E}",
+ 'dodekthai' => "\x{0E14}",
+ 'dohiragana' => "\x{3069}",
+ 'dokatakana' => "\x{30C9}",
+ 'dollarinferior' => "\x{F6E3}",
+ 'dollarmonospace' => "\x{FF04}",
+ 'dollaroldstyle' => "\x{F724}",
+ 'dollarsmall' => "\x{FE69}",
+ 'dollarsuperior' => "\x{F6E4}",
+ 'dorusquare' => "\x{3326}",
+ 'dotaccentcmb' => "\x{0307}",
+ 'dotbelowcmb' => "\x{0323}",
+ 'dotkatakana' => "\x{30FB}",
+ 'dotlessj' => "\x{F6BE}",
+ 'dotlessjstrokehook' => "\x{0284}",
+ 'dottedcircle' => "\x{25CC}",
+ 'doubleyodpatah' => "\x{FB1F}",
+ 'doubleyodpatahhebrew' => "\x{FB1F}",
+ 'downtackbelowcmb' => "\x{031E}",
+ 'downtackmod' => "\x{02D5}",
+ 'dparen' => "\x{249F}",
+ 'dsuperior' => "\x{F6EB}",
+ 'dtail' => "\x{0256}",
+ 'dtopbar' => "\x{018C}",
+ 'duhiragana' => "\x{3065}",
+ 'dukatakana' => "\x{30C5}",
+ 'dz' => "\x{01F3}",
+ 'dzaltone' => "\x{02A3}",
+ 'dzcaron' => "\x{01C6}",
+ 'dzcurl' => "\x{02A5}",
+ 'dzeabkhasiancyrillic' => "\x{04E1}",
+ 'dzecyrillic' => "\x{0455}",
+ 'dzhecyrillic' => "\x{045F}",
+ 'earth' => "\x{2641}",
+ 'ebengali' => "\x{098F}",
+ 'ebopomofo' => "\x{311C}",
+ 'ecandradeva' => "\x{090D}",
+ 'ecandragujarati' => "\x{0A8D}",
+ 'ecandravowelsigndeva' => "\x{0945}",
+ 'ecandravowelsigngujarati' => "\x{0AC5}",
+ 'ecedillabreve' => "\x{1E1D}",
+ 'echarmenian' => "\x{0565}",
+ 'echyiwnarmenian' => "\x{0587}",
+ 'ecircle' => "\x{24D4}",
+ 'ecircumflexacute' => "\x{1EBF}",
+ 'ecircumflexbelow' => "\x{1E19}",
+ 'ecircumflexdotbelow' => "\x{1EC7}",
+ 'ecircumflexgrave' => "\x{1EC1}",
+ 'ecircumflexhookabove' => "\x{1EC3}",
+ 'ecircumflextilde' => "\x{1EC5}",
+ 'ecyrillic' => "\x{0454}",
+ 'edblgrave' => "\x{0205}",
+ 'edeva' => "\x{090F}",
+ 'edot' => "\x{0117}",
+ 'edotbelow' => "\x{1EB9}",
+ 'eegurmukhi' => "\x{0A0F}",
+ 'eematragurmukhi' => "\x{0A47}",
+ 'efcyrillic' => "\x{0444}",
+ 'egujarati' => "\x{0A8F}",
+ 'eharmenian' => "\x{0567}",
+ 'ehbopomofo' => "\x{311D}",
+ 'ehiragana' => "\x{3048}",
+ 'ehookabove' => "\x{1EBB}",
+ 'eibopomofo' => "\x{311F}",
+ 'eightarabic' => "\x{0668}",
+ 'eightbengali' => "\x{09EE}",
+ 'eightcircle' => "\x{2467}",
+ 'eightcircleinversesansserif' => "\x{2791}",
+ 'eightdeva' => "\x{096E}",
+ 'eighteencircle' => "\x{2471}",
+ 'eighteenparen' => "\x{2485}",
+ 'eighteenperiod' => "\x{2499}",
+ 'eightgujarati' => "\x{0AEE}",
+ 'eightgurmukhi' => "\x{0A6E}",
+ 'eighthackarabic' => "\x{0668}",
+ 'eighthangzhou' => "\x{3028}",
+ 'eighthnotebeamed' => "\x{266B}",
+ 'eightideographicparen' => "\x{3227}",
+ 'eightinferior' => "\x{2088}",
+ 'eightmonospace' => "\x{FF18}",
+ 'eightoldstyle' => "\x{F738}",
+ 'eightparen' => "\x{247B}",
+ 'eightperiod' => "\x{248F}",
+ 'eightpersian' => "\x{06F8}",
+ 'eightroman' => "\x{2177}",
+ 'eightsuperior' => "\x{2078}",
+ 'eightthai' => "\x{0E58}",
+ 'einvertedbreve' => "\x{0207}",
+ 'eiotifiedcyrillic' => "\x{0465}",
+ 'ekatakana' => "\x{30A8}",
+ 'ekatakanahalfwidth' => "\x{FF74}",
+ 'ekonkargurmukhi' => "\x{0A74}",
+ 'ekorean' => "\x{3154}",
+ 'elcyrillic' => "\x{043B}",
+ 'elevencircle' => "\x{246A}",
+ 'elevenparen' => "\x{247E}",
+ 'elevenperiod' => "\x{2492}",
+ 'elevenroman' => "\x{217A}",
+ 'ellipsisvertical' => "\x{22EE}",
+ 'emacronacute' => "\x{1E17}",
+ 'emacrongrave' => "\x{1E15}",
+ 'emcyrillic' => "\x{043C}",
+ 'emdashvertical' => "\x{FE31}",
+ 'emonospace' => "\x{FF45}",
+ 'emphasismarkarmenian' => "\x{055B}",
+ 'enbopomofo' => "\x{3123}",
+ 'encyrillic' => "\x{043D}",
+ 'endashvertical' => "\x{FE32}",
+ 'endescendercyrillic' => "\x{04A3}",
+ 'engbopomofo' => "\x{3125}",
+ 'enghecyrillic' => "\x{04A5}",
+ 'enhookcyrillic' => "\x{04C8}",
+ 'enspace' => "\x{2002}",
+ 'eokorean' => "\x{3153}",
+ 'eopen' => "\x{025B}",
+ 'eopenclosed' => "\x{029A}",
+ 'eopenreversed' => "\x{025C}",
+ 'eopenreversedclosed' => "\x{025E}",
+ 'eopenreversedhook' => "\x{025D}",
+ 'eparen' => "\x{24A0}",
+ 'equalmonospace' => "\x{FF1D}",
+ 'equalsmall' => "\x{FE66}",
+ 'equalsuperior' => "\x{207C}",
+ 'erbopomofo' => "\x{3126}",
+ 'ercyrillic' => "\x{0440}",
+ 'ereversed' => "\x{0258}",
+ 'ereversedcyrillic' => "\x{044D}",
+ 'escyrillic' => "\x{0441}",
+ 'esdescendercyrillic' => "\x{04AB}",
+ 'esh' => "\x{0283}",
+ 'eshcurl' => "\x{0286}",
+ 'eshortdeva' => "\x{090E}",
+ 'eshortvowelsigndeva' => "\x{0946}",
+ 'eshreversedloop' => "\x{01AA}",
+ 'eshsquatreversed' => "\x{0285}",
+ 'esmallhiragana' => "\x{3047}",
+ 'esmallkatakana' => "\x{30A7}",
+ 'esmallkatakanahalfwidth' => "\x{FF6A}",
+ 'esuperior' => "\x{F6EC}",
+ 'etarmenian' => "\x{0568}",
+ 'etilde' => "\x{1EBD}",
+ 'etildebelow' => "\x{1E1B}",
+ 'etnahtafoukhhebrew' => "\x{0591}",
+ 'etnahtafoukhlefthebrew' => "\x{0591}",
+ 'etnahtahebrew' => "\x{0591}",
+ 'etnahtalefthebrew' => "\x{0591}",
+ 'eturned' => "\x{01DD}",
+ 'eukorean' => "\x{3161}",
+ 'euro' => "\x{20AC}",
+ 'evowelsignbengali' => "\x{09C7}",
+ 'evowelsigndeva' => "\x{0947}",
+ 'evowelsigngujarati' => "\x{0AC7}",
+ 'exclamarmenian' => "\x{055C}",
+ 'exclamdownsmall' => "\x{F7A1}",
+ 'exclammonospace' => "\x{FF01}",
+ 'exclamsmall' => "\x{F721}",
+ 'ezh' => "\x{0292}",
+ 'ezhcaron' => "\x{01EF}",
+ 'ezhcurl' => "\x{0293}",
+ 'ezhreversed' => "\x{01B9}",
+ 'ezhtail' => "\x{01BA}",
+ 'fadeva' => "\x{095E}",
+ 'fagurmukhi' => "\x{0A5E}",
+ 'fahrenheit' => "\x{2109}",
+ 'fathaarabic' => "\x{064E}",
+ 'fathalowarabic' => "\x{064E}",
+ 'fathatanarabic' => "\x{064B}",
+ 'fbopomofo' => "\x{3108}",
+ 'fcircle' => "\x{24D5}",
+ 'fdotaccent' => "\x{1E1F}",
+ 'feharabic' => "\x{0641}",
+ 'feharmenian' => "\x{0586}",
+ 'fehfinalarabic' => "\x{FED2}",
+ 'fehinitialarabic' => "\x{FED3}",
+ 'fehmedialarabic' => "\x{FED4}",
+ 'feicoptic' => "\x{03E5}",
+ 'fifteencircle' => "\x{246E}",
+ 'fifteenparen' => "\x{2482}",
+ 'fifteenperiod' => "\x{2496}",
+ 'finalkaf' => "\x{05DA}",
+ 'finalkafdagesh' => "\x{FB3A}",
+ 'finalkafdageshhebrew' => "\x{FB3A}",
+ 'finalkafhebrew' => "\x{05DA}",
+ 'finalkafqamats' => "\x{05DA}\x{05B8}",
+ 'finalkafqamatshebrew' => "\x{05DA}\x{05B8}",
+ 'finalkafsheva' => "\x{05DA}\x{05B0}",
+ 'finalkafshevahebrew' => "\x{05DA}\x{05B0}",
+ 'finalmem' => "\x{05DD}",
+ 'finalmemhebrew' => "\x{05DD}",
+ 'finalnun' => "\x{05DF}",
+ 'finalnunhebrew' => "\x{05DF}",
+ 'finalpe' => "\x{05E3}",
+ 'finalpehebrew' => "\x{05E3}",
+ 'finaltsadi' => "\x{05E5}",
+ 'finaltsadihebrew' => "\x{05E5}",
+ 'firsttonechinese' => "\x{02C9}",
+ 'fisheye' => "\x{25C9}",
+ 'fitacyrillic' => "\x{0473}",
+ 'fivearabic' => "\x{0665}",
+ 'fivebengali' => "\x{09EB}",
+ 'fivecircle' => "\x{2464}",
+ 'fivecircleinversesansserif' => "\x{278E}",
+ 'fivedeva' => "\x{096B}",
+ 'fivegujarati' => "\x{0AEB}",
+ 'fivegurmukhi' => "\x{0A6B}",
+ 'fivehackarabic' => "\x{0665}",
+ 'fivehangzhou' => "\x{3025}",
+ 'fiveideographicparen' => "\x{3224}",
+ 'fiveinferior' => "\x{2085}",
+ 'fivemonospace' => "\x{FF15}",
+ 'fiveoldstyle' => "\x{F735}",
+ 'fiveparen' => "\x{2478}",
+ 'fiveperiod' => "\x{248C}",
+ 'fivepersian' => "\x{06F5}",
+ 'fiveroman' => "\x{2174}",
+ 'fivesuperior' => "\x{2075}",
+ 'fivethai' => "\x{0E55}",
+ 'fmonospace' => "\x{FF46}",
+ 'fmsquare' => "\x{3399}",
+ 'fofanthai' => "\x{0E1F}",
+ 'fofathai' => "\x{0E1D}",
+ 'fongmanthai' => "\x{0E4F}",
+ 'forall' => "\x{2200}",
+ 'fourarabic' => "\x{0664}",
+ 'fourbengali' => "\x{09EA}",
+ 'fourcircle' => "\x{2463}",
+ 'fourcircleinversesansserif' => "\x{278D}",
+ 'fourdeva' => "\x{096A}",
+ 'fourgujarati' => "\x{0AEA}",
+ 'fourgurmukhi' => "\x{0A6A}",
+ 'fourhackarabic' => "\x{0664}",
+ 'fourhangzhou' => "\x{3024}",
+ 'fourideographicparen' => "\x{3223}",
+ 'fourinferior' => "\x{2084}",
+ 'fourmonospace' => "\x{FF14}",
+ 'fournumeratorbengali' => "\x{09F7}",
+ 'fouroldstyle' => "\x{F734}",
+ 'fourparen' => "\x{2477}",
+ 'fourperiod' => "\x{248B}",
+ 'fourpersian' => "\x{06F4}",
+ 'fourroman' => "\x{2173}",
+ 'foursuperior' => "\x{2074}",
+ 'fourteencircle' => "\x{246D}",
+ 'fourteenparen' => "\x{2481}",
+ 'fourteenperiod' => "\x{2495}",
+ 'fourthai' => "\x{0E54}",
+ 'fourthtonechinese' => "\x{02CB}",
+ 'fparen' => "\x{24A1}",
+ 'gabengali' => "\x{0997}",
+ 'gacute' => "\x{01F5}",
+ 'gadeva' => "\x{0917}",
+ 'gafarabic' => "\x{06AF}",
+ 'gaffinalarabic' => "\x{FB93}",
+ 'gafinitialarabic' => "\x{FB94}",
+ 'gafmedialarabic' => "\x{FB95}",
+ 'gagujarati' => "\x{0A97}",
+ 'gagurmukhi' => "\x{0A17}",
+ 'gahiragana' => "\x{304C}",
+ 'gakatakana' => "\x{30AC}",
+ 'gammalatinsmall' => "\x{0263}",
+ 'gammasuperior' => "\x{02E0}",
+ 'gangiacoptic' => "\x{03EB}",
+ 'gbopomofo' => "\x{310D}",
+ 'gcedilla' => "\x{0123}",
+ 'gcircle' => "\x{24D6}",
+ 'gdot' => "\x{0121}",
+ 'gecyrillic' => "\x{0433}",
+ 'gehiragana' => "\x{3052}",
+ 'gekatakana' => "\x{30B2}",
+ 'geometricallyequal' => "\x{2251}",
+ 'gereshaccenthebrew' => "\x{059C}",
+ 'gereshhebrew' => "\x{05F3}",
+ 'gereshmuqdamhebrew' => "\x{059D}",
+ 'gershayimaccenthebrew' => "\x{059E}",
+ 'gershayimhebrew' => "\x{05F4}",
+ 'getamark' => "\x{3013}",
+ 'ghabengali' => "\x{0998}",
+ 'ghadarmenian' => "\x{0572}",
+ 'ghadeva' => "\x{0918}",
+ 'ghagujarati' => "\x{0A98}",
+ 'ghagurmukhi' => "\x{0A18}",
+ 'ghainarabic' => "\x{063A}",
+ 'ghainfinalarabic' => "\x{FECE}",
+ 'ghaininitialarabic' => "\x{FECF}",
+ 'ghainmedialarabic' => "\x{FED0}",
+ 'ghemiddlehookcyrillic' => "\x{0495}",
+ 'ghestrokecyrillic' => "\x{0493}",
+ 'gheupturncyrillic' => "\x{0491}",
+ 'ghhadeva' => "\x{095A}",
+ 'ghhagurmukhi' => "\x{0A5A}",
+ 'ghook' => "\x{0260}",
+ 'ghzsquare' => "\x{3393}",
+ 'gihiragana' => "\x{304E}",
+ 'gikatakana' => "\x{30AE}",
+ 'gimarmenian' => "\x{0563}",
+ 'gimel' => "\x{05D2}",
+ 'gimeldagesh' => "\x{FB32}",
+ 'gimeldageshhebrew' => "\x{FB32}",
+ 'gimelhebrew' => "\x{05D2}",
+ 'gjecyrillic' => "\x{0453}",
+ 'glottalinvertedstroke' => "\x{01BE}",
+ 'glottalstop' => "\x{0294}",
+ 'glottalstopinverted' => "\x{0296}",
+ 'glottalstopmod' => "\x{02C0}",
+ 'glottalstopreversed' => "\x{0295}",
+ 'glottalstopreversedmod' => "\x{02C1}",
+ 'glottalstopreversedsuperior' => "\x{02E4}",
+ 'glottalstopstroke' => "\x{02A1}",
+ 'glottalstopstrokereversed' => "\x{02A2}",
+ 'gmacron' => "\x{1E21}",
+ 'gmonospace' => "\x{FF47}",
+ 'gohiragana' => "\x{3054}",
+ 'gokatakana' => "\x{30B4}",
+ 'gparen' => "\x{24A2}",
+ 'gpasquare' => "\x{33AC}",
+ 'gravebelowcmb' => "\x{0316}",
+ 'gravecmb' => "\x{0300}",
+ 'gravedeva' => "\x{0953}",
+ 'gravelowmod' => "\x{02CE}",
+ 'gravemonospace' => "\x{FF40}",
+ 'gravetonecmb' => "\x{0340}",
+ 'greaterequalorless' => "\x{22DB}",
+ 'greatermonospace' => "\x{FF1E}",
+ 'greaterorequivalent' => "\x{2273}",
+ 'greaterorless' => "\x{2277}",
+ 'greateroverequal' => "\x{2267}",
+ 'greatersmall' => "\x{FE65}",
+ 'gscript' => "\x{0261}",
+ 'gstroke' => "\x{01E5}",
+ 'guhiragana' => "\x{3050}",
+ 'gukatakana' => "\x{30B0}",
+ 'guramusquare' => "\x{3318}",
+ 'gysquare' => "\x{33C9}",
+ 'haabkhasiancyrillic' => "\x{04A9}",
+ 'haaltonearabic' => "\x{06C1}",
+ 'habengali' => "\x{09B9}",
+ 'hadescendercyrillic' => "\x{04B3}",
+ 'hadeva' => "\x{0939}",
+ 'hagujarati' => "\x{0AB9}",
+ 'hagurmukhi' => "\x{0A39}",
+ 'haharabic' => "\x{062D}",
+ 'hahfinalarabic' => "\x{FEA2}",
+ 'hahinitialarabic' => "\x{FEA3}",
+ 'hahiragana' => "\x{306F}",
+ 'hahmedialarabic' => "\x{FEA4}",
+ 'haitusquare' => "\x{332A}",
+ 'hakatakana' => "\x{30CF}",
+ 'hakatakanahalfwidth' => "\x{FF8A}",
+ 'halantgurmukhi' => "\x{0A4D}",
+ 'hamzaarabic' => "\x{0621}",
+ 'hamzadammaarabic' => "\x{0621}\x{064F}",
+ 'hamzadammatanarabic' => "\x{0621}\x{064C}",
+ 'hamzafathaarabic' => "\x{0621}\x{064E}",
+ 'hamzafathatanarabic' => "\x{0621}\x{064B}",
+ 'hamzalowarabic' => "\x{0621}",
+ 'hamzalowkasraarabic' => "\x{0621}\x{0650}",
+ 'hamzalowkasratanarabic' => "\x{0621}\x{064D}",
+ 'hamzasukunarabic' => "\x{0621}\x{0652}",
+ 'hangulfiller' => "\x{3164}",
+ 'hardsigncyrillic' => "\x{044A}",
+ 'harpoonleftbarbup' => "\x{21BC}",
+ 'harpoonrightbarbup' => "\x{21C0}",
+ 'hasquare' => "\x{33CA}",
+ 'hatafpatah' => "\x{05B2}",
+ 'hatafpatah16' => "\x{05B2}",
+ 'hatafpatah23' => "\x{05B2}",
+ 'hatafpatah2f' => "\x{05B2}",
+ 'hatafpatahhebrew' => "\x{05B2}",
+ 'hatafpatahnarrowhebrew' => "\x{05B2}",
+ 'hatafpatahquarterhebrew' => "\x{05B2}",
+ 'hatafpatahwidehebrew' => "\x{05B2}",
+ 'hatafqamats' => "\x{05B3}",
+ 'hatafqamats1b' => "\x{05B3}",
+ 'hatafqamats28' => "\x{05B3}",
+ 'hatafqamats34' => "\x{05B3}",
+ 'hatafqamatshebrew' => "\x{05B3}",
+ 'hatafqamatsnarrowhebrew' => "\x{05B3}",
+ 'hatafqamatsquarterhebrew' => "\x{05B3}",
+ 'hatafqamatswidehebrew' => "\x{05B3}",
+ 'hatafsegol' => "\x{05B1}",
+ 'hatafsegol17' => "\x{05B1}",
+ 'hatafsegol24' => "\x{05B1}",
+ 'hatafsegol30' => "\x{05B1}",
+ 'hatafsegolhebrew' => "\x{05B1}",
+ 'hatafsegolnarrowhebrew' => "\x{05B1}",
+ 'hatafsegolquarterhebrew' => "\x{05B1}",
+ 'hatafsegolwidehebrew' => "\x{05B1}",
+ 'hbopomofo' => "\x{310F}",
+ 'hbrevebelow' => "\x{1E2B}",
+ 'hcedilla' => "\x{1E29}",
+ 'hcircle' => "\x{24D7}",
+ 'hdieresis' => "\x{1E27}",
+ 'hdotaccent' => "\x{1E23}",
+ 'hdotbelow' => "\x{1E25}",
+ 'he' => "\x{05D4}",
+ 'heartsuitblack' => "\x{2665}",
+ 'heartsuitwhite' => "\x{2661}",
+ 'hedagesh' => "\x{FB34}",
+ 'hedageshhebrew' => "\x{FB34}",
+ 'hehaltonearabic' => "\x{06C1}",
+ 'heharabic' => "\x{0647}",
+ 'hehebrew' => "\x{05D4}",
+ 'hehfinalaltonearabic' => "\x{FBA7}",
+ 'hehfinalalttwoarabic' => "\x{FEEA}",
+ 'hehfinalarabic' => "\x{FEEA}",
+ 'hehhamzaabovefinalarabic' => "\x{FBA5}",
+ 'hehhamzaaboveisolatedarabic' => "\x{FBA4}",
+ 'hehinitialaltonearabic' => "\x{FBA8}",
+ 'hehinitialarabic' => "\x{FEEB}",
+ 'hehiragana' => "\x{3078}",
+ 'hehmedialaltonearabic' => "\x{FBA9}",
+ 'hehmedialarabic' => "\x{FEEC}",
+ 'heiseierasquare' => "\x{337B}",
+ 'hekatakana' => "\x{30D8}",
+ 'hekatakanahalfwidth' => "\x{FF8D}",
+ 'hekutaarusquare' => "\x{3336}",
+ 'henghook' => "\x{0267}",
+ 'herutusquare' => "\x{3339}",
+ 'het' => "\x{05D7}",
+ 'hethebrew' => "\x{05D7}",
+ 'hhook' => "\x{0266}",
+ 'hhooksuperior' => "\x{02B1}",
+ 'hieuhacirclekorean' => "\x{327B}",
+ 'hieuhaparenkorean' => "\x{321B}",
+ 'hieuhcirclekorean' => "\x{326D}",
+ 'hieuhkorean' => "\x{314E}",
+ 'hieuhparenkorean' => "\x{320D}",
+ 'hihiragana' => "\x{3072}",
+ 'hikatakana' => "\x{30D2}",
+ 'hikatakanahalfwidth' => "\x{FF8B}",
+ 'hiriq' => "\x{05B4}",
+ 'hiriq14' => "\x{05B4}",
+ 'hiriq21' => "\x{05B4}",
+ 'hiriq2d' => "\x{05B4}",
+ 'hiriqhebrew' => "\x{05B4}",
+ 'hiriqnarrowhebrew' => "\x{05B4}",
+ 'hiriqquarterhebrew' => "\x{05B4}",
+ 'hiriqwidehebrew' => "\x{05B4}",
+ 'hlinebelow' => "\x{1E96}",
+ 'hmonospace' => "\x{FF48}",
+ 'hoarmenian' => "\x{0570}",
+ 'hohipthai' => "\x{0E2B}",
+ 'hohiragana' => "\x{307B}",
+ 'hokatakana' => "\x{30DB}",
+ 'hokatakanahalfwidth' => "\x{FF8E}",
+ 'holam' => "\x{05B9}",
+ 'holam19' => "\x{05B9}",
+ 'holam26' => "\x{05B9}",
+ 'holam32' => "\x{05B9}",
+ 'holamhebrew' => "\x{05B9}",
+ 'holamnarrowhebrew' => "\x{05B9}",
+ 'holamquarterhebrew' => "\x{05B9}",
+ 'holamwidehebrew' => "\x{05B9}",
+ 'honokhukthai' => "\x{0E2E}",
+ 'hookcmb' => "\x{0309}",
+ 'hookpalatalizedbelowcmb' => "\x{0321}",
+ 'hookretroflexbelowcmb' => "\x{0322}",
+ 'hoonsquare' => "\x{3342}",
+ 'horicoptic' => "\x{03E9}",
+ 'horizontalbar' => "\x{2015}",
+ 'horncmb' => "\x{031B}",
+ 'hotsprings' => "\x{2668}",
+ 'hparen' => "\x{24A3}",
+ 'hsuperior' => "\x{02B0}",
+ 'hturned' => "\x{0265}",
+ 'huhiragana' => "\x{3075}",
+ 'huiitosquare' => "\x{3333}",
+ 'hukatakana' => "\x{30D5}",
+ 'hukatakanahalfwidth' => "\x{FF8C}",
+ 'hungarumlautcmb' => "\x{030B}",
+ 'hv' => "\x{0195}",
+ 'hypheninferior' => "\x{F6E5}",
+ 'hyphenmonospace' => "\x{FF0D}",
+ 'hyphensmall' => "\x{FE63}",
+ 'hyphensuperior' => "\x{F6E6}",
+ 'hyphentwo' => "\x{2010}",
+ 'iacyrillic' => "\x{044F}",
+ 'ibengali' => "\x{0987}",
+ 'ibopomofo' => "\x{3127}",
+ 'icaron' => "\x{01D0}",
+ 'icircle' => "\x{24D8}",
+ 'icyrillic' => "\x{0456}",
+ 'idblgrave' => "\x{0209}",
+ 'ideographearthcircle' => "\x{328F}",
+ 'ideographfirecircle' => "\x{328B}",
+ 'ideographicallianceparen' => "\x{323F}",
+ 'ideographiccallparen' => "\x{323A}",
+ 'ideographiccentrecircle' => "\x{32A5}",
+ 'ideographicclose' => "\x{3006}",
+ 'ideographiccomma' => "\x{3001}",
+ 'ideographiccommaleft' => "\x{FF64}",
+ 'ideographiccongratulationparen' => "\x{3237}",
+ 'ideographiccorrectcircle' => "\x{32A3}",
+ 'ideographicearthparen' => "\x{322F}",
+ 'ideographicenterpriseparen' => "\x{323D}",
+ 'ideographicexcellentcircle' => "\x{329D}",
+ 'ideographicfestivalparen' => "\x{3240}",
+ 'ideographicfinancialcircle' => "\x{3296}",
+ 'ideographicfinancialparen' => "\x{3236}",
+ 'ideographicfireparen' => "\x{322B}",
+ 'ideographichaveparen' => "\x{3232}",
+ 'ideographichighcircle' => "\x{32A4}",
+ 'ideographiciterationmark' => "\x{3005}",
+ 'ideographiclaborcircle' => "\x{3298}",
+ 'ideographiclaborparen' => "\x{3238}",
+ 'ideographicleftcircle' => "\x{32A7}",
+ 'ideographiclowcircle' => "\x{32A6}",
+ 'ideographicmedicinecircle' => "\x{32A9}",
+ 'ideographicmetalparen' => "\x{322E}",
+ 'ideographicmoonparen' => "\x{322A}",
+ 'ideographicnameparen' => "\x{3234}",
+ 'ideographicperiod' => "\x{3002}",
+ 'ideographicprintcircle' => "\x{329E}",
+ 'ideographicreachparen' => "\x{3243}",
+ 'ideographicrepresentparen' => "\x{3239}",
+ 'ideographicresourceparen' => "\x{323E}",
+ 'ideographicrightcircle' => "\x{32A8}",
+ 'ideographicsecretcircle' => "\x{3299}",
+ 'ideographicselfparen' => "\x{3242}",
+ 'ideographicsocietyparen' => "\x{3233}",
+ 'ideographicspace' => "\x{3000}",
+ 'ideographicspecialparen' => "\x{3235}",
+ 'ideographicstockparen' => "\x{3231}",
+ 'ideographicstudyparen' => "\x{323B}",
+ 'ideographicsunparen' => "\x{3230}",
+ 'ideographicsuperviseparen' => "\x{323C}",
+ 'ideographicwaterparen' => "\x{322C}",
+ 'ideographicwoodparen' => "\x{322D}",
+ 'ideographiczero' => "\x{3007}",
+ 'ideographmetalcircle' => "\x{328E}",
+ 'ideographmooncircle' => "\x{328A}",
+ 'ideographnamecircle' => "\x{3294}",
+ 'ideographsuncircle' => "\x{3290}",
+ 'ideographwatercircle' => "\x{328C}",
+ 'ideographwoodcircle' => "\x{328D}",
+ 'ideva' => "\x{0907}",
+ 'idieresisacute' => "\x{1E2F}",
+ 'idieresiscyrillic' => "\x{04E5}",
+ 'idotbelow' => "\x{1ECB}",
+ 'iebrevecyrillic' => "\x{04D7}",
+ 'iecyrillic' => "\x{0435}",
+ 'ieungacirclekorean' => "\x{3275}",
+ 'ieungaparenkorean' => "\x{3215}",
+ 'ieungcirclekorean' => "\x{3267}",
+ 'ieungkorean' => "\x{3147}",
+ 'ieungparenkorean' => "\x{3207}",
+ 'igujarati' => "\x{0A87}",
+ 'igurmukhi' => "\x{0A07}",
+ 'ihiragana' => "\x{3044}",
+ 'ihookabove' => "\x{1EC9}",
+ 'iibengali' => "\x{0988}",
+ 'iicyrillic' => "\x{0438}",
+ 'iideva' => "\x{0908}",
+ 'iigujarati' => "\x{0A88}",
+ 'iigurmukhi' => "\x{0A08}",
+ 'iimatragurmukhi' => "\x{0A40}",
+ 'iinvertedbreve' => "\x{020B}",
+ 'iishortcyrillic' => "\x{0439}",
+ 'iivowelsignbengali' => "\x{09C0}",
+ 'iivowelsigndeva' => "\x{0940}",
+ 'iivowelsigngujarati' => "\x{0AC0}",
+ 'ikatakana' => "\x{30A4}",
+ 'ikatakanahalfwidth' => "\x{FF72}",
+ 'ikorean' => "\x{3163}",
+ 'ilde' => "\x{02DC}",
+ 'iluyhebrew' => "\x{05AC}",
+ 'imacroncyrillic' => "\x{04E3}",
+ 'imageorapproximatelyequal' => "\x{2253}",
+ 'imatragurmukhi' => "\x{0A3F}",
+ 'imonospace' => "\x{FF49}",
+ 'increment' => "\x{2206}",
+ 'iniarmenian' => "\x{056B}",
+ 'integralbottom' => "\x{2321}",
+ 'integralex' => "\x{F8F5}",
+ 'integraltop' => "\x{2320}",
+ 'intisquare' => "\x{3305}",
+ 'iocyrillic' => "\x{0451}",
+ 'iotalatin' => "\x{0269}",
+ 'iparen' => "\x{24A4}",
+ 'irigurmukhi' => "\x{0A72}",
+ 'ismallhiragana' => "\x{3043}",
+ 'ismallkatakana' => "\x{30A3}",
+ 'ismallkatakanahalfwidth' => "\x{FF68}",
+ 'issharbengali' => "\x{09FA}",
+ 'istroke' => "\x{0268}",
+ 'isuperior' => "\x{F6ED}",
+ 'iterationhiragana' => "\x{309D}",
+ 'iterationkatakana' => "\x{30FD}",
+ 'itildebelow' => "\x{1E2D}",
+ 'iubopomofo' => "\x{3129}",
+ 'iucyrillic' => "\x{044E}",
+ 'ivowelsignbengali' => "\x{09BF}",
+ 'ivowelsigndeva' => "\x{093F}",
+ 'ivowelsigngujarati' => "\x{0ABF}",
+ 'izhitsacyrillic' => "\x{0475}",
+ 'izhitsadblgravecyrillic' => "\x{0477}",
+ 'jaarmenian' => "\x{0571}",
+ 'jabengali' => "\x{099C}",
+ 'jadeva' => "\x{091C}",
+ 'jagujarati' => "\x{0A9C}",
+ 'jagurmukhi' => "\x{0A1C}",
+ 'jbopomofo' => "\x{3110}",
+ 'jcaron' => "\x{01F0}",
+ 'jcircle' => "\x{24D9}",
+ 'jcrossedtail' => "\x{029D}",
+ 'jdotlessstroke' => "\x{025F}",
+ 'jecyrillic' => "\x{0458}",
+ 'jeemarabic' => "\x{062C}",
+ 'jeemfinalarabic' => "\x{FE9E}",
+ 'jeeminitialarabic' => "\x{FE9F}",
+ 'jeemmedialarabic' => "\x{FEA0}",
+ 'jeharabic' => "\x{0698}",
+ 'jehfinalarabic' => "\x{FB8B}",
+ 'jhabengali' => "\x{099D}",
+ 'jhadeva' => "\x{091D}",
+ 'jhagujarati' => "\x{0A9D}",
+ 'jhagurmukhi' => "\x{0A1D}",
+ 'jheharmenian' => "\x{057B}",
+ 'jis' => "\x{3004}",
+ 'jmonospace' => "\x{FF4A}",
+ 'jparen' => "\x{24A5}",
+ 'jsuperior' => "\x{02B2}",
+ 'kabashkircyrillic' => "\x{04A1}",
+ 'kabengali' => "\x{0995}",
+ 'kacute' => "\x{1E31}",
+ 'kacyrillic' => "\x{043A}",
+ 'kadescendercyrillic' => "\x{049B}",
+ 'kadeva' => "\x{0915}",
+ 'kaf' => "\x{05DB}",
+ 'kafarabic' => "\x{0643}",
+ 'kafdagesh' => "\x{FB3B}",
+ 'kafdageshhebrew' => "\x{FB3B}",
+ 'kaffinalarabic' => "\x{FEDA}",
+ 'kafhebrew' => "\x{05DB}",
+ 'kafinitialarabic' => "\x{FEDB}",
+ 'kafmedialarabic' => "\x{FEDC}",
+ 'kafrafehebrew' => "\x{FB4D}",
+ 'kagujarati' => "\x{0A95}",
+ 'kagurmukhi' => "\x{0A15}",
+ 'kahiragana' => "\x{304B}",
+ 'kahookcyrillic' => "\x{04C4}",
+ 'kakatakana' => "\x{30AB}",
+ 'kakatakanahalfwidth' => "\x{FF76}",
+ 'kappasymbolgreek' => "\x{03F0}",
+ 'kapyeounmieumkorean' => "\x{3171}",
+ 'kapyeounphieuphkorean' => "\x{3184}",
+ 'kapyeounpieupkorean' => "\x{3178}",
+ 'kapyeounssangpieupkorean' => "\x{3179}",
+ 'karoriisquare' => "\x{330D}",
+ 'kashidaautoarabic' => "\x{0640}",
+ 'kashidaautonosidebearingarabic' => "\x{0640}",
+ 'kasmallkatakana' => "\x{30F5}",
+ 'kasquare' => "\x{3384}",
+ 'kasraarabic' => "\x{0650}",
+ 'kasratanarabic' => "\x{064D}",
+ 'kastrokecyrillic' => "\x{049F}",
+ 'katahiraprolongmarkhalfwidth' => "\x{FF70}",
+ 'kaverticalstrokecyrillic' => "\x{049D}",
+ 'kbopomofo' => "\x{310E}",
+ 'kcalsquare' => "\x{3389}",
+ 'kcaron' => "\x{01E9}",
+ 'kcedilla' => "\x{0137}",
+ 'kcircle' => "\x{24DA}",
+ 'kdotbelow' => "\x{1E33}",
+ 'keharmenian' => "\x{0584}",
+ 'kehiragana' => "\x{3051}",
+ 'kekatakana' => "\x{30B1}",
+ 'kekatakanahalfwidth' => "\x{FF79}",
+ 'kenarmenian' => "\x{056F}",
+ 'kesmallkatakana' => "\x{30F6}",
+ 'khabengali' => "\x{0996}",
+ 'khacyrillic' => "\x{0445}",
+ 'khadeva' => "\x{0916}",
+ 'khagujarati' => "\x{0A96}",
+ 'khagurmukhi' => "\x{0A16}",
+ 'khaharabic' => "\x{062E}",
+ 'khahfinalarabic' => "\x{FEA6}",
+ 'khahinitialarabic' => "\x{FEA7}",
+ 'khahmedialarabic' => "\x{FEA8}",
+ 'kheicoptic' => "\x{03E7}",
+ 'khhadeva' => "\x{0959}",
+ 'khhagurmukhi' => "\x{0A59}",
+ 'khieukhacirclekorean' => "\x{3278}",
+ 'khieukhaparenkorean' => "\x{3218}",
+ 'khieukhcirclekorean' => "\x{326A}",
+ 'khieukhkorean' => "\x{314B}",
+ 'khieukhparenkorean' => "\x{320A}",
+ 'khokhaithai' => "\x{0E02}",
+ 'khokhonthai' => "\x{0E05}",
+ 'khokhuatthai' => "\x{0E03}",
+ 'khokhwaithai' => "\x{0E04}",
+ 'khomutthai' => "\x{0E5B}",
+ 'khook' => "\x{0199}",
+ 'khorakhangthai' => "\x{0E06}",
+ 'khzsquare' => "\x{3391}",
+ 'kihiragana' => "\x{304D}",
+ 'kikatakana' => "\x{30AD}",
+ 'kikatakanahalfwidth' => "\x{FF77}",
+ 'kiroguramusquare' => "\x{3315}",
+ 'kiromeetorusquare' => "\x{3316}",
+ 'kirosquare' => "\x{3314}",
+ 'kiyeokacirclekorean' => "\x{326E}",
+ 'kiyeokaparenkorean' => "\x{320E}",
+ 'kiyeokcirclekorean' => "\x{3260}",
+ 'kiyeokkorean' => "\x{3131}",
+ 'kiyeokparenkorean' => "\x{3200}",
+ 'kiyeoksioskorean' => "\x{3133}",
+ 'kjecyrillic' => "\x{045C}",
+ 'klinebelow' => "\x{1E35}",
+ 'klsquare' => "\x{3398}",
+ 'kmcubedsquare' => "\x{33A6}",
+ 'kmonospace' => "\x{FF4B}",
+ 'kmsquaredsquare' => "\x{33A2}",
+ 'kohiragana' => "\x{3053}",
+ 'kohmsquare' => "\x{33C0}",
+ 'kokaithai' => "\x{0E01}",
+ 'kokatakana' => "\x{30B3}",
+ 'kokatakanahalfwidth' => "\x{FF7A}",
+ 'kooposquare' => "\x{331E}",
+ 'koppacyrillic' => "\x{0481}",
+ 'koreanstandardsymbol' => "\x{327F}",
+ 'koroniscmb' => "\x{0343}",
+ 'kparen' => "\x{24A6}",
+ 'kpasquare' => "\x{33AA}",
+ 'ksicyrillic' => "\x{046F}",
+ 'ktsquare' => "\x{33CF}",
+ 'kturned' => "\x{029E}",
+ 'kuhiragana' => "\x{304F}",
+ 'kukatakana' => "\x{30AF}",
+ 'kukatakanahalfwidth' => "\x{FF78}",
+ 'kvsquare' => "\x{33B8}",
+ 'kwsquare' => "\x{33BE}",
+ 'labengali' => "\x{09B2}",
+ 'ladeva' => "\x{0932}",
+ 'lagujarati' => "\x{0AB2}",
+ 'lagurmukhi' => "\x{0A32}",
+ 'lakkhangyaothai' => "\x{0E45}",
+ 'lamaleffinalarabic' => "\x{FEFC}",
+ 'lamalefhamzaabovefinalarabic' => "\x{FEF8}",
+ 'lamalefhamzaaboveisolatedarabic' => "\x{FEF7}",
+ 'lamalefhamzabelowfinalarabic' => "\x{FEFA}",
+ 'lamalefhamzabelowisolatedarabic' => "\x{FEF9}",
+ 'lamalefisolatedarabic' => "\x{FEFB}",
+ 'lamalefmaddaabovefinalarabic' => "\x{FEF6}",
+ 'lamalefmaddaaboveisolatedarabic' => "\x{FEF5}",
+ 'lamarabic' => "\x{0644}",
+ 'lambdastroke' => "\x{019B}",
+ 'lamed' => "\x{05DC}",
+ 'lameddagesh' => "\x{FB3C}",
+ 'lameddageshhebrew' => "\x{FB3C}",
+ 'lamedhebrew' => "\x{05DC}",
+ 'lamedholam' => "\x{05DC}\x{05B9}",
+ 'lamedholamdagesh' => "\x{05DC}\x{05B9}\x{05BC}",
+ 'lamedholamdageshhebrew' => "\x{05DC}\x{05B9}\x{05BC}",
+ 'lamedholamhebrew' => "\x{05DC}\x{05B9}",
+ 'lamfinalarabic' => "\x{FEDE}",
+ 'lamhahinitialarabic' => "\x{FCCA}",
+ 'laminitialarabic' => "\x{FEDF}",
+ 'lamjeeminitialarabic' => "\x{FCC9}",
+ 'lamkhahinitialarabic' => "\x{FCCB}",
+ 'lamlamhehisolatedarabic' => "\x{FDF2}",
+ 'lammedialarabic' => "\x{FEE0}",
+ 'lammeemhahinitialarabic' => "\x{FD88}",
+ 'lammeeminitialarabic' => "\x{FCCC}",
+ 'lammeemjeeminitialarabic' => "\x{FEDF}\x{FEE4}\x{FEA0}",
+ 'lammeemkhahinitialarabic' => "\x{FEDF}\x{FEE4}\x{FEA8}",
+ 'largecircle' => "\x{25EF}",
+ 'lbar' => "\x{019A}",
+ 'lbelt' => "\x{026C}",
+ 'lbopomofo' => "\x{310C}",
+ 'lcedilla' => "\x{013C}",
+ 'lcircle' => "\x{24DB}",
+ 'lcircumflexbelow' => "\x{1E3D}",
+ 'ldotaccent' => "\x{0140}",
+ 'ldotbelow' => "\x{1E37}",
+ 'ldotbelowmacron' => "\x{1E39}",
+ 'leftangleabovecmb' => "\x{031A}",
+ 'lefttackbelowcmb' => "\x{0318}",
+ 'lessequalorgreater' => "\x{22DA}",
+ 'lessmonospace' => "\x{FF1C}",
+ 'lessorequivalent' => "\x{2272}",
+ 'lessorgreater' => "\x{2276}",
+ 'lessoverequal' => "\x{2266}",
+ 'lesssmall' => "\x{FE64}",
+ 'lezh' => "\x{026E}",
+ 'lhookretroflex' => "\x{026D}",
+ 'liwnarmenian' => "\x{056C}",
+ 'lj' => "\x{01C9}",
+ 'ljecyrillic' => "\x{0459}",
+ 'll' => "\x{F6C0}",
+ 'lladeva' => "\x{0933}",
+ 'llagujarati' => "\x{0AB3}",
+ 'llinebelow' => "\x{1E3B}",
+ 'llladeva' => "\x{0934}",
+ 'llvocalicbengali' => "\x{09E1}",
+ 'llvocalicdeva' => "\x{0961}",
+ 'llvocalicvowelsignbengali' => "\x{09E3}",
+ 'llvocalicvowelsigndeva' => "\x{0963}",
+ 'lmiddletilde' => "\x{026B}",
+ 'lmonospace' => "\x{FF4C}",
+ 'lmsquare' => "\x{33D0}",
+ 'lochulathai' => "\x{0E2C}",
+ 'logicalnotreversed' => "\x{2310}",
+ 'lolingthai' => "\x{0E25}",
+ 'lowlinecenterline' => "\x{FE4E}",
+ 'lowlinecmb' => "\x{0332}",
+ 'lowlinedashed' => "\x{FE4D}",
+ 'lparen' => "\x{24A7}",
+ 'lsquare' => "\x{2113}",
+ 'lsuperior' => "\x{F6EE}",
+ 'luthai' => "\x{0E26}",
+ 'lvocalicbengali' => "\x{098C}",
+ 'lvocalicdeva' => "\x{090C}",
+ 'lvocalicvowelsignbengali' => "\x{09E2}",
+ 'lvocalicvowelsigndeva' => "\x{0962}",
+ 'lxsquare' => "\x{33D3}",
+ 'mabengali' => "\x{09AE}",
+ 'macronbelowcmb' => "\x{0331}",
+ 'macroncmb' => "\x{0304}",
+ 'macronlowmod' => "\x{02CD}",
+ 'macronmonospace' => "\x{FFE3}",
+ 'macute' => "\x{1E3F}",
+ 'madeva' => "\x{092E}",
+ 'magujarati' => "\x{0AAE}",
+ 'magurmukhi' => "\x{0A2E}",
+ 'mahapakhhebrew' => "\x{05A4}",
+ 'mahapakhlefthebrew' => "\x{05A4}",
+ 'mahiragana' => "\x{307E}",
+ 'maichattawalowleftthai' => "\x{F895}",
+ 'maichattawalowrightthai' => "\x{F894}",
+ 'maichattawathai' => "\x{0E4B}",
+ 'maichattawaupperleftthai' => "\x{F893}",
+ 'maieklowleftthai' => "\x{F88C}",
+ 'maieklowrightthai' => "\x{F88B}",
+ 'maiekthai' => "\x{0E48}",
+ 'maiekupperleftthai' => "\x{F88A}",
+ 'maihanakatleftthai' => "\x{F884}",
+ 'maihanakatthai' => "\x{0E31}",
+ 'maitaikhuleftthai' => "\x{F889}",
+ 'maitaikhuthai' => "\x{0E47}",
+ 'maitholowleftthai' => "\x{F88F}",
+ 'maitholowrightthai' => "\x{F88E}",
+ 'maithothai' => "\x{0E49}",
+ 'maithoupperleftthai' => "\x{F88D}",
+ 'maitrilowleftthai' => "\x{F892}",
+ 'maitrilowrightthai' => "\x{F891}",
+ 'maitrithai' => "\x{0E4A}",
+ 'maitriupperleftthai' => "\x{F890}",
+ 'maiyamokthai' => "\x{0E46}",
+ 'makatakana' => "\x{30DE}",
+ 'makatakanahalfwidth' => "\x{FF8F}",
+ 'mansyonsquare' => "\x{3347}",
+ 'maqafhebrew' => "\x{05BE}",
+ 'mars' => "\x{2642}",
+ 'masoracirclehebrew' => "\x{05AF}",
+ 'masquare' => "\x{3383}",
+ 'mbopomofo' => "\x{3107}",
+ 'mbsquare' => "\x{33D4}",
+ 'mcircle' => "\x{24DC}",
+ 'mcubedsquare' => "\x{33A5}",
+ 'mdotaccent' => "\x{1E41}",
+ 'mdotbelow' => "\x{1E43}",
+ 'meemarabic' => "\x{0645}",
+ 'meemfinalarabic' => "\x{FEE2}",
+ 'meeminitialarabic' => "\x{FEE3}",
+ 'meemmedialarabic' => "\x{FEE4}",
+ 'meemmeeminitialarabic' => "\x{FCD1}",
+ 'meemmeemisolatedarabic' => "\x{FC48}",
+ 'meetorusquare' => "\x{334D}",
+ 'mehiragana' => "\x{3081}",
+ 'meizierasquare' => "\x{337E}",
+ 'mekatakana' => "\x{30E1}",
+ 'mekatakanahalfwidth' => "\x{FF92}",
+ 'mem' => "\x{05DE}",
+ 'memdagesh' => "\x{FB3E}",
+ 'memdageshhebrew' => "\x{FB3E}",
+ 'memhebrew' => "\x{05DE}",
+ 'menarmenian' => "\x{0574}",
+ 'merkhahebrew' => "\x{05A5}",
+ 'merkhakefulahebrew' => "\x{05A6}",
+ 'merkhakefulalefthebrew' => "\x{05A6}",
+ 'merkhalefthebrew' => "\x{05A5}",
+ 'mhook' => "\x{0271}",
+ 'mhzsquare' => "\x{3392}",
+ 'middledotkatakanahalfwidth' => "\x{FF65}",
+ 'middot' => "\x{00B7}",
+ 'mieumacirclekorean' => "\x{3272}",
+ 'mieumaparenkorean' => "\x{3212}",
+ 'mieumcirclekorean' => "\x{3264}",
+ 'mieumkorean' => "\x{3141}",
+ 'mieumpansioskorean' => "\x{3170}",
+ 'mieumparenkorean' => "\x{3204}",
+ 'mieumpieupkorean' => "\x{316E}",
+ 'mieumsioskorean' => "\x{316F}",
+ 'mihiragana' => "\x{307F}",
+ 'mikatakana' => "\x{30DF}",
+ 'mikatakanahalfwidth' => "\x{FF90}",
+ 'minusbelowcmb' => "\x{0320}",
+ 'minuscircle' => "\x{2296}",
+ 'minusmod' => "\x{02D7}",
+ 'minusplus' => "\x{2213}",
+ 'miribaarusquare' => "\x{334A}",
+ 'mirisquare' => "\x{3349}",
+ 'mlonglegturned' => "\x{0270}",
+ 'mlsquare' => "\x{3396}",
+ 'mmcubedsquare' => "\x{33A3}",
+ 'mmonospace' => "\x{FF4D}",
+ 'mmsquaredsquare' => "\x{339F}",
+ 'mohiragana' => "\x{3082}",
+ 'mohmsquare' => "\x{33C1}",
+ 'mokatakana' => "\x{30E2}",
+ 'mokatakanahalfwidth' => "\x{FF93}",
+ 'molsquare' => "\x{33D6}",
+ 'momathai' => "\x{0E21}",
+ 'moverssquare' => "\x{33A7}",
+ 'moverssquaredsquare' => "\x{33A8}",
+ 'mparen' => "\x{24A8}",
+ 'mpasquare' => "\x{33AB}",
+ 'mssquare' => "\x{33B3}",
+ 'msuperior' => "\x{F6EF}",
+ 'mturned' => "\x{026F}",
+ 'mu1' => "\x{00B5}",
+ 'muasquare' => "\x{3382}",
+ 'muchgreater' => "\x{226B}",
+ 'muchless' => "\x{226A}",
+ 'mufsquare' => "\x{338C}",
+ 'mugreek' => "\x{03BC}",
+ 'mugsquare' => "\x{338D}",
+ 'muhiragana' => "\x{3080}",
+ 'mukatakana' => "\x{30E0}",
+ 'mukatakanahalfwidth' => "\x{FF91}",
+ 'mulsquare' => "\x{3395}",
+ 'mumsquare' => "\x{339B}",
+ 'munahhebrew' => "\x{05A3}",
+ 'munahlefthebrew' => "\x{05A3}",
+ 'musicflatsign' => "\x{266D}",
+ 'musicsharpsign' => "\x{266F}",
+ 'mussquare' => "\x{33B2}",
+ 'muvsquare' => "\x{33B6}",
+ 'muwsquare' => "\x{33BC}",
+ 'mvmegasquare' => "\x{33B9}",
+ 'mvsquare' => "\x{33B7}",
+ 'mwmegasquare' => "\x{33BF}",
+ 'mwsquare' => "\x{33BD}",
+ 'nabengali' => "\x{09A8}",
+ 'nabla' => "\x{2207}",
+ 'nadeva' => "\x{0928}",
+ 'nagujarati' => "\x{0AA8}",
+ 'nagurmukhi' => "\x{0A28}",
+ 'nahiragana' => "\x{306A}",
+ 'nakatakana' => "\x{30CA}",
+ 'nakatakanahalfwidth' => "\x{FF85}",
+ 'nasquare' => "\x{3381}",
+ 'nbopomofo' => "\x{310B}",
+ 'nbspace' => "\x{00A0}",
+ 'ncedilla' => "\x{0146}",
+ 'ncircle' => "\x{24DD}",
+ 'ncircumflexbelow' => "\x{1E4B}",
+ 'ndotaccent' => "\x{1E45}",
+ 'ndotbelow' => "\x{1E47}",
+ 'nehiragana' => "\x{306D}",
+ 'nekatakana' => "\x{30CD}",
+ 'nekatakanahalfwidth' => "\x{FF88}",
+ 'newsheqelsign' => "\x{20AA}",
+ 'nfsquare' => "\x{338B}",
+ 'ngabengali' => "\x{0999}",
+ 'ngadeva' => "\x{0919}",
+ 'ngagujarati' => "\x{0A99}",
+ 'ngagurmukhi' => "\x{0A19}",
+ 'ngonguthai' => "\x{0E07}",
+ 'nhiragana' => "\x{3093}",
+ 'nhookleft' => "\x{0272}",
+ 'nhookretroflex' => "\x{0273}",
+ 'nieunacirclekorean' => "\x{326F}",
+ 'nieunaparenkorean' => "\x{320F}",
+ 'nieuncieuckorean' => "\x{3135}",
+ 'nieuncirclekorean' => "\x{3261}",
+ 'nieunhieuhkorean' => "\x{3136}",
+ 'nieunkorean' => "\x{3134}",
+ 'nieunpansioskorean' => "\x{3168}",
+ 'nieunparenkorean' => "\x{3201}",
+ 'nieunsioskorean' => "\x{3167}",
+ 'nieuntikeutkorean' => "\x{3166}",
+ 'nihiragana' => "\x{306B}",
+ 'nikatakana' => "\x{30CB}",
+ 'nikatakanahalfwidth' => "\x{FF86}",
+ 'nikhahitleftthai' => "\x{F899}",
+ 'nikhahitthai' => "\x{0E4D}",
+ 'ninearabic' => "\x{0669}",
+ 'ninebengali' => "\x{09EF}",
+ 'ninecircle' => "\x{2468}",
+ 'ninecircleinversesansserif' => "\x{2792}",
+ 'ninedeva' => "\x{096F}",
+ 'ninegujarati' => "\x{0AEF}",
+ 'ninegurmukhi' => "\x{0A6F}",
+ 'ninehackarabic' => "\x{0669}",
+ 'ninehangzhou' => "\x{3029}",
+ 'nineideographicparen' => "\x{3228}",
+ 'nineinferior' => "\x{2089}",
+ 'ninemonospace' => "\x{FF19}",
+ 'nineoldstyle' => "\x{F739}",
+ 'nineparen' => "\x{247C}",
+ 'nineperiod' => "\x{2490}",
+ 'ninepersian' => "\x{06F9}",
+ 'nineroman' => "\x{2178}",
+ 'ninesuperior' => "\x{2079}",
+ 'nineteencircle' => "\x{2472}",
+ 'nineteenparen' => "\x{2486}",
+ 'nineteenperiod' => "\x{249A}",
+ 'ninethai' => "\x{0E59}",
+ 'nj' => "\x{01CC}",
+ 'njecyrillic' => "\x{045A}",
+ 'nkatakana' => "\x{30F3}",
+ 'nkatakanahalfwidth' => "\x{FF9D}",
+ 'nlegrightlong' => "\x{019E}",
+ 'nlinebelow' => "\x{1E49}",
+ 'nmonospace' => "\x{FF4E}",
+ 'nmsquare' => "\x{339A}",
+ 'nnabengali' => "\x{09A3}",
+ 'nnadeva' => "\x{0923}",
+ 'nnagujarati' => "\x{0AA3}",
+ 'nnagurmukhi' => "\x{0A23}",
+ 'nnnadeva' => "\x{0929}",
+ 'nohiragana' => "\x{306E}",
+ 'nokatakana' => "\x{30CE}",
+ 'nokatakanahalfwidth' => "\x{FF89}",
+ 'nonbreakingspace' => "\x{00A0}",
+ 'nonenthai' => "\x{0E13}",
+ 'nonuthai' => "\x{0E19}",
+ 'noonarabic' => "\x{0646}",
+ 'noonfinalarabic' => "\x{FEE6}",
+ 'noonghunnaarabic' => "\x{06BA}",
+ 'noonghunnafinalarabic' => "\x{FB9F}",
+ 'noonhehinitialarabic' => "\x{FEE7}\x{FEEC}",
+ 'nooninitialarabic' => "\x{FEE7}",
+ 'noonjeeminitialarabic' => "\x{FCD2}",
+ 'noonjeemisolatedarabic' => "\x{FC4B}",
+ 'noonmedialarabic' => "\x{FEE8}",
+ 'noonmeeminitialarabic' => "\x{FCD5}",
+ 'noonmeemisolatedarabic' => "\x{FC4E}",
+ 'noonnoonfinalarabic' => "\x{FC8D}",
+ 'notcontains' => "\x{220C}",
+ 'notelementof' => "\x{2209}",
+ 'notgreater' => "\x{226F}",
+ 'notgreaternorequal' => "\x{2271}",
+ 'notgreaternorless' => "\x{2279}",
+ 'notidentical' => "\x{2262}",
+ 'notless' => "\x{226E}",
+ 'notlessnorequal' => "\x{2270}",
+ 'notparallel' => "\x{2226}",
+ 'notprecedes' => "\x{2280}",
+ 'notsucceeds' => "\x{2281}",
+ 'notsuperset' => "\x{2285}",
+ 'nowarmenian' => "\x{0576}",
+ 'nparen' => "\x{24A9}",
+ 'nssquare' => "\x{33B1}",
+ 'nsuperior' => "\x{207F}",
+ 'nuhiragana' => "\x{306C}",
+ 'nukatakana' => "\x{30CC}",
+ 'nukatakanahalfwidth' => "\x{FF87}",
+ 'nuktabengali' => "\x{09BC}",
+ 'nuktadeva' => "\x{093C}",
+ 'nuktagujarati' => "\x{0ABC}",
+ 'nuktagurmukhi' => "\x{0A3C}",
+ 'numbersignmonospace' => "\x{FF03}",
+ 'numbersignsmall' => "\x{FE5F}",
+ 'numeralsigngreek' => "\x{0374}",
+ 'numeralsignlowergreek' => "\x{0375}",
+ 'numero' => "\x{2116}",
+ 'nun' => "\x{05E0}",
+ 'nundagesh' => "\x{FB40}",
+ 'nundageshhebrew' => "\x{FB40}",
+ 'nunhebrew' => "\x{05E0}",
+ 'nvsquare' => "\x{33B5}",
+ 'nwsquare' => "\x{33BB}",
+ 'nyabengali' => "\x{099E}",
+ 'nyadeva' => "\x{091E}",
+ 'nyagujarati' => "\x{0A9E}",
+ 'nyagurmukhi' => "\x{0A1E}",
+ 'oangthai' => "\x{0E2D}",
+ 'obarred' => "\x{0275}",
+ 'obarredcyrillic' => "\x{04E9}",
+ 'obarreddieresiscyrillic' => "\x{04EB}",
+ 'obengali' => "\x{0993}",
+ 'obopomofo' => "\x{311B}",
+ 'ocandradeva' => "\x{0911}",
+ 'ocandragujarati' => "\x{0A91}",
+ 'ocandravowelsigndeva' => "\x{0949}",
+ 'ocandravowelsigngujarati' => "\x{0AC9}",
+ 'ocaron' => "\x{01D2}",
+ 'ocircle' => "\x{24DE}",
+ 'ocircumflexacute' => "\x{1ED1}",
+ 'ocircumflexdotbelow' => "\x{1ED9}",
+ 'ocircumflexgrave' => "\x{1ED3}",
+ 'ocircumflexhookabove' => "\x{1ED5}",
+ 'ocircumflextilde' => "\x{1ED7}",
+ 'ocyrillic' => "\x{043E}",
+ 'odblacute' => "\x{0151}",
+ 'odblgrave' => "\x{020D}",
+ 'odeva' => "\x{0913}",
+ 'odieresiscyrillic' => "\x{04E7}",
+ 'odotbelow' => "\x{1ECD}",
+ 'oekorean' => "\x{315A}",
+ 'ogonekcmb' => "\x{0328}",
+ 'ogujarati' => "\x{0A93}",
+ 'oharmenian' => "\x{0585}",
+ 'ohiragana' => "\x{304A}",
+ 'ohookabove' => "\x{1ECF}",
+ 'ohornacute' => "\x{1EDB}",
+ 'ohorndotbelow' => "\x{1EE3}",
+ 'ohorngrave' => "\x{1EDD}",
+ 'ohornhookabove' => "\x{1EDF}",
+ 'ohorntilde' => "\x{1EE1}",
+ 'oi' => "\x{01A3}",
+ 'oinvertedbreve' => "\x{020F}",
+ 'okatakana' => "\x{30AA}",
+ 'okatakanahalfwidth' => "\x{FF75}",
+ 'okorean' => "\x{3157}",
+ 'olehebrew' => "\x{05AB}",
+ 'omacronacute' => "\x{1E53}",
+ 'omacrongrave' => "\x{1E51}",
+ 'omdeva' => "\x{0950}",
+ 'omegacyrillic' => "\x{0461}",
+ 'omegalatinclosed' => "\x{0277}",
+ 'omegaroundcyrillic' => "\x{047B}",
+ 'omegatitlocyrillic' => "\x{047D}",
+ 'omgujarati' => "\x{0AD0}",
+ 'omonospace' => "\x{FF4F}",
+ 'onearabic' => "\x{0661}",
+ 'onebengali' => "\x{09E7}",
+ 'onecircle' => "\x{2460}",
+ 'onecircleinversesansserif' => "\x{278A}",
+ 'onedeva' => "\x{0967}",
+ 'onefitted' => "\x{F6DC}",
+ 'onegujarati' => "\x{0AE7}",
+ 'onegurmukhi' => "\x{0A67}",
+ 'onehackarabic' => "\x{0661}",
+ 'onehangzhou' => "\x{3021}",
+ 'oneideographicparen' => "\x{3220}",
+ 'oneinferior' => "\x{2081}",
+ 'onemonospace' => "\x{FF11}",
+ 'onenumeratorbengali' => "\x{09F4}",
+ 'oneoldstyle' => "\x{F731}",
+ 'oneparen' => "\x{2474}",
+ 'oneperiod' => "\x{2488}",
+ 'onepersian' => "\x{06F1}",
+ 'oneroman' => "\x{2170}",
+ 'onethai' => "\x{0E51}",
+ 'oogonek' => "\x{01EB}",
+ 'oogonekmacron' => "\x{01ED}",
+ 'oogurmukhi' => "\x{0A13}",
+ 'oomatragurmukhi' => "\x{0A4B}",
+ 'oopen' => "\x{0254}",
+ 'oparen' => "\x{24AA}",
+ 'option' => "\x{2325}",
+ 'oshortdeva' => "\x{0912}",
+ 'oshortvowelsigndeva' => "\x{094A}",
+ 'osmallhiragana' => "\x{3049}",
+ 'osmallkatakana' => "\x{30A9}",
+ 'osmallkatakanahalfwidth' => "\x{FF6B}",
+ 'ostrokeacute' => "\x{01FF}",
+ 'osuperior' => "\x{F6F0}",
+ 'otcyrillic' => "\x{047F}",
+ 'otildeacute' => "\x{1E4D}",
+ 'otildedieresis' => "\x{1E4F}",
+ 'oubopomofo' => "\x{3121}",
+ 'overline' => "\x{203E}",
+ 'overlinecenterline' => "\x{FE4A}",
+ 'overlinecmb' => "\x{0305}",
+ 'overlinedashed' => "\x{FE49}",
+ 'overlinedblwavy' => "\x{FE4C}",
+ 'overlinewavy' => "\x{FE4B}",
+ 'overscore' => "\x{00AF}",
+ 'ovowelsignbengali' => "\x{09CB}",
+ 'ovowelsigndeva' => "\x{094B}",
+ 'ovowelsigngujarati' => "\x{0ACB}",
+ 'paampssquare' => "\x{3380}",
+ 'paasentosquare' => "\x{332B}",
+ 'pabengali' => "\x{09AA}",
+ 'pacute' => "\x{1E55}",
+ 'padeva' => "\x{092A}",
+ 'pagedown' => "\x{21DF}",
+ 'pageup' => "\x{21DE}",
+ 'pagujarati' => "\x{0AAA}",
+ 'pagurmukhi' => "\x{0A2A}",
+ 'pahiragana' => "\x{3071}",
+ 'paiyannoithai' => "\x{0E2F}",
+ 'pakatakana' => "\x{30D1}",
+ 'palatalizationcyrilliccmb' => "\x{0484}",
+ 'palochkacyrillic' => "\x{04C0}",
+ 'pansioskorean' => "\x{317F}",
+ 'parallel' => "\x{2225}",
+ 'parenleftaltonearabic' => "\x{FD3E}",
+ 'parenleftbt' => "\x{F8ED}",
+ 'parenleftex' => "\x{F8EC}",
+ 'parenleftinferior' => "\x{208D}",
+ 'parenleftmonospace' => "\x{FF08}",
+ 'parenleftsmall' => "\x{FE59}",
+ 'parenleftsuperior' => "\x{207D}",
+ 'parenlefttp' => "\x{F8EB}",
+ 'parenleftvertical' => "\x{FE35}",
+ 'parenrightaltonearabic' => "\x{FD3F}",
+ 'parenrightbt' => "\x{F8F8}",
+ 'parenrightex' => "\x{F8F7}",
+ 'parenrightinferior' => "\x{208E}",
+ 'parenrightmonospace' => "\x{FF09}",
+ 'parenrightsmall' => "\x{FE5A}",
+ 'parenrightsuperior' => "\x{207E}",
+ 'parenrighttp' => "\x{F8F6}",
+ 'parenrightvertical' => "\x{FE36}",
+ 'paseqhebrew' => "\x{05C0}",
+ 'pashtahebrew' => "\x{0599}",
+ 'pasquare' => "\x{33A9}",
+ 'patah' => "\x{05B7}",
+ 'patah11' => "\x{05B7}",
+ 'patah1d' => "\x{05B7}",
+ 'patah2a' => "\x{05B7}",
+ 'patahhebrew' => "\x{05B7}",
+ 'patahnarrowhebrew' => "\x{05B7}",
+ 'patahquarterhebrew' => "\x{05B7}",
+ 'patahwidehebrew' => "\x{05B7}",
+ 'pazerhebrew' => "\x{05A1}",
+ 'pbopomofo' => "\x{3106}",
+ 'pcircle' => "\x{24DF}",
+ 'pdotaccent' => "\x{1E57}",
+ 'pe' => "\x{05E4}",
+ 'pecyrillic' => "\x{043F}",
+ 'pedagesh' => "\x{FB44}",
+ 'pedageshhebrew' => "\x{FB44}",
+ 'peezisquare' => "\x{333B}",
+ 'pefinaldageshhebrew' => "\x{FB43}",
+ 'peharabic' => "\x{067E}",
+ 'peharmenian' => "\x{057A}",
+ 'pehebrew' => "\x{05E4}",
+ 'pehfinalarabic' => "\x{FB57}",
+ 'pehinitialarabic' => "\x{FB58}",
+ 'pehiragana' => "\x{307A}",
+ 'pehmedialarabic' => "\x{FB59}",
+ 'pekatakana' => "\x{30DA}",
+ 'pemiddlehookcyrillic' => "\x{04A7}",
+ 'perafehebrew' => "\x{FB4E}",
+ 'percentarabic' => "\x{066A}",
+ 'percentmonospace' => "\x{FF05}",
+ 'percentsmall' => "\x{FE6A}",
+ 'periodarmenian' => "\x{0589}",
+ 'periodhalfwidth' => "\x{FF61}",
+ 'periodinferior' => "\x{F6E7}",
+ 'periodmonospace' => "\x{FF0E}",
+ 'periodsmall' => "\x{FE52}",
+ 'periodsuperior' => "\x{F6E8}",
+ 'perispomenigreekcmb' => "\x{0342}",
+ 'pfsquare' => "\x{338A}",
+ 'phabengali' => "\x{09AB}",
+ 'phadeva' => "\x{092B}",
+ 'phagujarati' => "\x{0AAB}",
+ 'phagurmukhi' => "\x{0A2B}",
+ 'phieuphacirclekorean' => "\x{327A}",
+ 'phieuphaparenkorean' => "\x{321A}",
+ 'phieuphcirclekorean' => "\x{326C}",
+ 'phieuphkorean' => "\x{314D}",
+ 'phieuphparenkorean' => "\x{320C}",
+ 'philatin' => "\x{0278}",
+ 'phinthuthai' => "\x{0E3A}",
+ 'phisymbolgreek' => "\x{03D5}",
+ 'phook' => "\x{01A5}",
+ 'phophanthai' => "\x{0E1E}",
+ 'phophungthai' => "\x{0E1C}",
+ 'phosamphaothai' => "\x{0E20}",
+ 'pieupacirclekorean' => "\x{3273}",
+ 'pieupaparenkorean' => "\x{3213}",
+ 'pieupcieuckorean' => "\x{3176}",
+ 'pieupcirclekorean' => "\x{3265}",
+ 'pieupkiyeokkorean' => "\x{3172}",
+ 'pieupkorean' => "\x{3142}",
+ 'pieupparenkorean' => "\x{3205}",
+ 'pieupsioskiyeokkorean' => "\x{3174}",
+ 'pieupsioskorean' => "\x{3144}",
+ 'pieupsiostikeutkorean' => "\x{3175}",
+ 'pieupthieuthkorean' => "\x{3177}",
+ 'pieuptikeutkorean' => "\x{3173}",
+ 'pihiragana' => "\x{3074}",
+ 'pikatakana' => "\x{30D4}",
+ 'pisymbolgreek' => "\x{03D6}",
+ 'piwrarmenian' => "\x{0583}",
+ 'plusbelowcmb' => "\x{031F}",
+ 'pluscircle' => "\x{2295}",
+ 'plusmod' => "\x{02D6}",
+ 'plusmonospace' => "\x{FF0B}",
+ 'plussmall' => "\x{FE62}",
+ 'plussuperior' => "\x{207A}",
+ 'pmonospace' => "\x{FF50}",
+ 'pmsquare' => "\x{33D8}",
+ 'pohiragana' => "\x{307D}",
+ 'pointingindexdownwhite' => "\x{261F}",
+ 'pointingindexleftwhite' => "\x{261C}",
+ 'pointingindexrightwhite' => "\x{261E}",
+ 'pointingindexupwhite' => "\x{261D}",
+ 'pokatakana' => "\x{30DD}",
+ 'poplathai' => "\x{0E1B}",
+ 'postalmark' => "\x{3012}",
+ 'postalmarkface' => "\x{3020}",
+ 'pparen' => "\x{24AB}",
+ 'precedes' => "\x{227A}",
+ 'primemod' => "\x{02B9}",
+ 'primereversed' => "\x{2035}",
+ 'projective' => "\x{2305}",
+ 'prolongedkana' => "\x{30FC}",
+ 'propellor' => "\x{2318}",
+ 'proportion' => "\x{2237}",
+ 'psicyrillic' => "\x{0471}",
+ 'psilipneumatacyrilliccmb' => "\x{0486}",
+ 'pssquare' => "\x{33B0}",
+ 'puhiragana' => "\x{3077}",
+ 'pukatakana' => "\x{30D7}",
+ 'pvsquare' => "\x{33B4}",
+ 'pwsquare' => "\x{33BA}",
+ 'qadeva' => "\x{0958}",
+ 'qadmahebrew' => "\x{05A8}",
+ 'qafarabic' => "\x{0642}",
+ 'qaffinalarabic' => "\x{FED6}",
+ 'qafinitialarabic' => "\x{FED7}",
+ 'qafmedialarabic' => "\x{FED8}",
+ 'qamats' => "\x{05B8}",
+ 'qamats10' => "\x{05B8}",
+ 'qamats1a' => "\x{05B8}",
+ 'qamats1c' => "\x{05B8}",
+ 'qamats27' => "\x{05B8}",
+ 'qamats29' => "\x{05B8}",
+ 'qamats33' => "\x{05B8}",
+ 'qamatsde' => "\x{05B8}",
+ 'qamatshebrew' => "\x{05B8}",
+ 'qamatsnarrowhebrew' => "\x{05B8}",
+ 'qamatsqatanhebrew' => "\x{05B8}",
+ 'qamatsqatannarrowhebrew' => "\x{05B8}",
+ 'qamatsqatanquarterhebrew' => "\x{05B8}",
+ 'qamatsqatanwidehebrew' => "\x{05B8}",
+ 'qamatsquarterhebrew' => "\x{05B8}",
+ 'qamatswidehebrew' => "\x{05B8}",
+ 'qarneyparahebrew' => "\x{059F}",
+ 'qbopomofo' => "\x{3111}",
+ 'qcircle' => "\x{24E0}",
+ 'qhook' => "\x{02A0}",
+ 'qmonospace' => "\x{FF51}",
+ 'qof' => "\x{05E7}",
+ 'qofdagesh' => "\x{FB47}",
+ 'qofdageshhebrew' => "\x{FB47}",
+ 'qofhatafpatah' => "\x{05E7}\x{05B2}",
+ 'qofhatafpatahhebrew' => "\x{05E7}\x{05B2}",
+ 'qofhatafsegol' => "\x{05E7}\x{05B1}",
+ 'qofhatafsegolhebrew' => "\x{05E7}\x{05B1}",
+ 'qofhebrew' => "\x{05E7}",
+ 'qofhiriq' => "\x{05E7}\x{05B4}",
+ 'qofhiriqhebrew' => "\x{05E7}\x{05B4}",
+ 'qofholam' => "\x{05E7}\x{05B9}",
+ 'qofholamhebrew' => "\x{05E7}\x{05B9}",
+ 'qofpatah' => "\x{05E7}\x{05B7}",
+ 'qofpatahhebrew' => "\x{05E7}\x{05B7}",
+ 'qofqamats' => "\x{05E7}\x{05B8}",
+ 'qofqamatshebrew' => "\x{05E7}\x{05B8}",
+ 'qofqubuts' => "\x{05E7}\x{05BB}",
+ 'qofqubutshebrew' => "\x{05E7}\x{05BB}",
+ 'qofsegol' => "\x{05E7}\x{05B6}",
+ 'qofsegolhebrew' => "\x{05E7}\x{05B6}",
+ 'qofsheva' => "\x{05E7}\x{05B0}",
+ 'qofshevahebrew' => "\x{05E7}\x{05B0}",
+ 'qoftsere' => "\x{05E7}\x{05B5}",
+ 'qoftserehebrew' => "\x{05E7}\x{05B5}",
+ 'qparen' => "\x{24AC}",
+ 'quarternote' => "\x{2669}",
+ 'qubuts' => "\x{05BB}",
+ 'qubuts18' => "\x{05BB}",
+ 'qubuts25' => "\x{05BB}",
+ 'qubuts31' => "\x{05BB}",
+ 'qubutshebrew' => "\x{05BB}",
+ 'qubutsnarrowhebrew' => "\x{05BB}",
+ 'qubutsquarterhebrew' => "\x{05BB}",
+ 'qubutswidehebrew' => "\x{05BB}",
+ 'questionarabic' => "\x{061F}",
+ 'questionarmenian' => "\x{055E}",
+ 'questiondownsmall' => "\x{F7BF}",
+ 'questiongreek' => "\x{037E}",
+ 'questionmonospace' => "\x{FF1F}",
+ 'questionsmall' => "\x{F73F}",
+ 'quotedblmonospace' => "\x{FF02}",
+ 'quotedblprime' => "\x{301E}",
+ 'quotedblprimereversed' => "\x{301D}",
+ 'quoteleftreversed' => "\x{201B}",
+ 'quoterightn' => "\x{0149}",
+ 'quotesinglemonospace' => "\x{FF07}",
+ 'raarmenian' => "\x{057C}",
+ 'rabengali' => "\x{09B0}",
+ 'radeva' => "\x{0930}",
+ 'radicalex' => "\x{F8E5}",
+ 'radoverssquare' => "\x{33AE}",
+ 'radoverssquaredsquare' => "\x{33AF}",
+ 'radsquare' => "\x{33AD}",
+ 'rafe' => "\x{05BF}",
+ 'rafehebrew' => "\x{05BF}",
+ 'ragujarati' => "\x{0AB0}",
+ 'ragurmukhi' => "\x{0A30}",
+ 'rahiragana' => "\x{3089}",
+ 'rakatakana' => "\x{30E9}",
+ 'rakatakanahalfwidth' => "\x{FF97}",
+ 'ralowerdiagonalbengali' => "\x{09F1}",
+ 'ramiddlediagonalbengali' => "\x{09F0}",
+ 'ramshorn' => "\x{0264}",
+ 'ratio' => "\x{2236}",
+ 'rbopomofo' => "\x{3116}",
+ 'rcedilla' => "\x{0157}",
+ 'rcircle' => "\x{24E1}",
+ 'rdblgrave' => "\x{0211}",
+ 'rdotaccent' => "\x{1E59}",
+ 'rdotbelow' => "\x{1E5B}",
+ 'rdotbelowmacron' => "\x{1E5D}",
+ 'referencemark' => "\x{203B}",
+ 'registersans' => "\x{F8E8}",
+ 'registerserif' => "\x{F6DA}",
+ 'reharabic' => "\x{0631}",
+ 'reharmenian' => "\x{0580}",
+ 'rehfinalarabic' => "\x{FEAE}",
+ 'rehiragana' => "\x{308C}",
+ 'rehyehaleflamarabic' => "\x{0631}\x{FEF3}\x{FE8E}\x{0644}",
+ 'rekatakana' => "\x{30EC}",
+ 'rekatakanahalfwidth' => "\x{FF9A}",
+ 'resh' => "\x{05E8}",
+ 'reshdageshhebrew' => "\x{FB48}",
+ 'reshhatafpatah' => "\x{05E8}\x{05B2}",
+ 'reshhatafpatahhebrew' => "\x{05E8}\x{05B2}",
+ 'reshhatafsegol' => "\x{05E8}\x{05B1}",
+ 'reshhatafsegolhebrew' => "\x{05E8}\x{05B1}",
+ 'reshhebrew' => "\x{05E8}",
+ 'reshhiriq' => "\x{05E8}\x{05B4}",
+ 'reshhiriqhebrew' => "\x{05E8}\x{05B4}",
+ 'reshholam' => "\x{05E8}\x{05B9}",
+ 'reshholamhebrew' => "\x{05E8}\x{05B9}",
+ 'reshpatah' => "\x{05E8}\x{05B7}",
+ 'reshpatahhebrew' => "\x{05E8}\x{05B7}",
+ 'reshqamats' => "\x{05E8}\x{05B8}",
+ 'reshqamatshebrew' => "\x{05E8}\x{05B8}",
+ 'reshqubuts' => "\x{05E8}\x{05BB}",
+ 'reshqubutshebrew' => "\x{05E8}\x{05BB}",
+ 'reshsegol' => "\x{05E8}\x{05B6}",
+ 'reshsegolhebrew' => "\x{05E8}\x{05B6}",
+ 'reshsheva' => "\x{05E8}\x{05B0}",
+ 'reshshevahebrew' => "\x{05E8}\x{05B0}",
+ 'reshtsere' => "\x{05E8}\x{05B5}",
+ 'reshtserehebrew' => "\x{05E8}\x{05B5}",
+ 'reversedtilde' => "\x{223D}",
+ 'reviahebrew' => "\x{0597}",
+ 'reviamugrashhebrew' => "\x{0597}",
+ 'rfishhook' => "\x{027E}",
+ 'rfishhookreversed' => "\x{027F}",
+ 'rhabengali' => "\x{09DD}",
+ 'rhadeva' => "\x{095D}",
+ 'rhook' => "\x{027D}",
+ 'rhookturned' => "\x{027B}",
+ 'rhookturnedsuperior' => "\x{02B5}",
+ 'rhosymbolgreek' => "\x{03F1}",
+ 'rhotichookmod' => "\x{02DE}",
+ 'rieulacirclekorean' => "\x{3271}",
+ 'rieulaparenkorean' => "\x{3211}",
+ 'rieulcirclekorean' => "\x{3263}",
+ 'rieulhieuhkorean' => "\x{3140}",
+ 'rieulkiyeokkorean' => "\x{313A}",
+ 'rieulkiyeoksioskorean' => "\x{3169}",
+ 'rieulkorean' => "\x{3139}",
+ 'rieulmieumkorean' => "\x{313B}",
+ 'rieulpansioskorean' => "\x{316C}",
+ 'rieulparenkorean' => "\x{3203}",
+ 'rieulphieuphkorean' => "\x{313F}",
+ 'rieulpieupkorean' => "\x{313C}",
+ 'rieulpieupsioskorean' => "\x{316B}",
+ 'rieulsioskorean' => "\x{313D}",
+ 'rieulthieuthkorean' => "\x{313E}",
+ 'rieultikeutkorean' => "\x{316A}",
+ 'rieulyeorinhieuhkorean' => "\x{316D}",
+ 'rightangle' => "\x{221F}",
+ 'righttackbelowcmb' => "\x{0319}",
+ 'righttriangle' => "\x{22BF}",
+ 'rihiragana' => "\x{308A}",
+ 'rikatakana' => "\x{30EA}",
+ 'rikatakanahalfwidth' => "\x{FF98}",
+ 'ringbelowcmb' => "\x{0325}",
+ 'ringcmb' => "\x{030A}",
+ 'ringhalfleft' => "\x{02BF}",
+ 'ringhalfleftarmenian' => "\x{0559}",
+ 'ringhalfleftbelowcmb' => "\x{031C}",
+ 'ringhalfleftcentered' => "\x{02D3}",
+ 'ringhalfright' => "\x{02BE}",
+ 'ringhalfrightbelowcmb' => "\x{0339}",
+ 'ringhalfrightcentered' => "\x{02D2}",
+ 'rinvertedbreve' => "\x{0213}",
+ 'rittorusquare' => "\x{3351}",
+ 'rlinebelow' => "\x{1E5F}",
+ 'rlongleg' => "\x{027C}",
+ 'rlonglegturned' => "\x{027A}",
+ 'rmonospace' => "\x{FF52}",
+ 'rohiragana' => "\x{308D}",
+ 'rokatakana' => "\x{30ED}",
+ 'rokatakanahalfwidth' => "\x{FF9B}",
+ 'roruathai' => "\x{0E23}",
+ 'rparen' => "\x{24AD}",
+ 'rrabengali' => "\x{09DC}",
+ 'rradeva' => "\x{0931}",
+ 'rragurmukhi' => "\x{0A5C}",
+ 'rreharabic' => "\x{0691}",
+ 'rrehfinalarabic' => "\x{FB8D}",
+ 'rrvocalicbengali' => "\x{09E0}",
+ 'rrvocalicdeva' => "\x{0960}",
+ 'rrvocalicgujarati' => "\x{0AE0}",
+ 'rrvocalicvowelsignbengali' => "\x{09C4}",
+ 'rrvocalicvowelsigndeva' => "\x{0944}",
+ 'rrvocalicvowelsigngujarati' => "\x{0AC4}",
+ 'rsuperior' => "\x{F6F1}",
+ 'rturned' => "\x{0279}",
+ 'rturnedsuperior' => "\x{02B4}",
+ 'ruhiragana' => "\x{308B}",
+ 'rukatakana' => "\x{30EB}",
+ 'rukatakanahalfwidth' => "\x{FF99}",
+ 'rupeemarkbengali' => "\x{09F2}",
+ 'rupeesignbengali' => "\x{09F3}",
+ 'rupiah' => "\x{F6DD}",
+ 'ruthai' => "\x{0E24}",
+ 'rvocalicbengali' => "\x{098B}",
+ 'rvocalicdeva' => "\x{090B}",
+ 'rvocalicgujarati' => "\x{0A8B}",
+ 'rvocalicvowelsignbengali' => "\x{09C3}",
+ 'rvocalicvowelsigndeva' => "\x{0943}",
+ 'rvocalicvowelsigngujarati' => "\x{0AC3}",
+ 'sabengali' => "\x{09B8}",
+ 'sacutedotaccent' => "\x{1E65}",
+ 'sadarabic' => "\x{0635}",
+ 'sadeva' => "\x{0938}",
+ 'sadfinalarabic' => "\x{FEBA}",
+ 'sadinitialarabic' => "\x{FEBB}",
+ 'sadmedialarabic' => "\x{FEBC}",
+ 'sagujarati' => "\x{0AB8}",
+ 'sagurmukhi' => "\x{0A38}",
+ 'sahiragana' => "\x{3055}",
+ 'sakatakana' => "\x{30B5}",
+ 'sakatakanahalfwidth' => "\x{FF7B}",
+ 'sallallahoualayhewasallamarabic' => "\x{FDFA}",
+ 'samekh' => "\x{05E1}",
+ 'samekhdagesh' => "\x{FB41}",
+ 'samekhdageshhebrew' => "\x{FB41}",
+ 'samekhhebrew' => "\x{05E1}",
+ 'saraaathai' => "\x{0E32}",
+ 'saraaethai' => "\x{0E41}",
+ 'saraaimaimalaithai' => "\x{0E44}",
+ 'saraaimaimuanthai' => "\x{0E43}",
+ 'saraamthai' => "\x{0E33}",
+ 'saraathai' => "\x{0E30}",
+ 'saraethai' => "\x{0E40}",
+ 'saraiileftthai' => "\x{F886}",
+ 'saraiithai' => "\x{0E35}",
+ 'saraileftthai' => "\x{F885}",
+ 'saraithai' => "\x{0E34}",
+ 'saraothai' => "\x{0E42}",
+ 'saraueeleftthai' => "\x{F888}",
+ 'saraueethai' => "\x{0E37}",
+ 'saraueleftthai' => "\x{F887}",
+ 'sarauethai' => "\x{0E36}",
+ 'sarauthai' => "\x{0E38}",
+ 'sarauuthai' => "\x{0E39}",
+ 'sbopomofo' => "\x{3119}",
+ 'scarondotaccent' => "\x{1E67}",
+ 'schwa' => "\x{0259}",
+ 'schwacyrillic' => "\x{04D9}",
+ 'schwadieresiscyrillic' => "\x{04DB}",
+ 'schwahook' => "\x{025A}",
+ 'scircle' => "\x{24E2}",
+ 'sdotaccent' => "\x{1E61}",
+ 'sdotbelow' => "\x{1E63}",
+ 'sdotbelowdotaccent' => "\x{1E69}",
+ 'seagullbelowcmb' => "\x{033C}",
+ 'secondtonechinese' => "\x{02CA}",
+ 'seenarabic' => "\x{0633}",
+ 'seenfinalarabic' => "\x{FEB2}",
+ 'seeninitialarabic' => "\x{FEB3}",
+ 'seenmedialarabic' => "\x{FEB4}",
+ 'segol' => "\x{05B6}",
+ 'segol13' => "\x{05B6}",
+ 'segol1f' => "\x{05B6}",
+ 'segol2c' => "\x{05B6}",
+ 'segolhebrew' => "\x{05B6}",
+ 'segolnarrowhebrew' => "\x{05B6}",
+ 'segolquarterhebrew' => "\x{05B6}",
+ 'segoltahebrew' => "\x{0592}",
+ 'segolwidehebrew' => "\x{05B6}",
+ 'seharmenian' => "\x{057D}",
+ 'sehiragana' => "\x{305B}",
+ 'sekatakana' => "\x{30BB}",
+ 'sekatakanahalfwidth' => "\x{FF7E}",
+ 'semicolonarabic' => "\x{061B}",
+ 'semicolonmonospace' => "\x{FF1B}",
+ 'semicolonsmall' => "\x{FE54}",
+ 'semivoicedmarkkana' => "\x{309C}",
+ 'semivoicedmarkkanahalfwidth' => "\x{FF9F}",
+ 'sentisquare' => "\x{3322}",
+ 'sentosquare' => "\x{3323}",
+ 'sevenarabic' => "\x{0667}",
+ 'sevenbengali' => "\x{09ED}",
+ 'sevencircle' => "\x{2466}",
+ 'sevencircleinversesansserif' => "\x{2790}",
+ 'sevendeva' => "\x{096D}",
+ 'sevengujarati' => "\x{0AED}",
+ 'sevengurmukhi' => "\x{0A6D}",
+ 'sevenhackarabic' => "\x{0667}",
+ 'sevenhangzhou' => "\x{3027}",
+ 'sevenideographicparen' => "\x{3226}",
+ 'seveninferior' => "\x{2087}",
+ 'sevenmonospace' => "\x{FF17}",
+ 'sevenoldstyle' => "\x{F737}",
+ 'sevenparen' => "\x{247A}",
+ 'sevenperiod' => "\x{248E}",
+ 'sevenpersian' => "\x{06F7}",
+ 'sevenroman' => "\x{2176}",
+ 'sevensuperior' => "\x{2077}",
+ 'seventeencircle' => "\x{2470}",
+ 'seventeenparen' => "\x{2484}",
+ 'seventeenperiod' => "\x{2498}",
+ 'seventhai' => "\x{0E57}",
+ 'sfthyphen' => "\x{00AD}",
+ 'shaarmenian' => "\x{0577}",
+ 'shabengali' => "\x{09B6}",
+ 'shacyrillic' => "\x{0448}",
+ 'shaddaarabic' => "\x{0651}",
+ 'shaddadammaarabic' => "\x{FC61}",
+ 'shaddadammatanarabic' => "\x{FC5E}",
+ 'shaddafathaarabic' => "\x{FC60}",
+ 'shaddafathatanarabic' => "\x{0651}\x{064B}",
+ 'shaddakasraarabic' => "\x{FC62}",
+ 'shaddakasratanarabic' => "\x{FC5F}",
+ 'shadedark' => "\x{2593}",
+ 'shadelight' => "\x{2591}",
+ 'shademedium' => "\x{2592}",
+ 'shadeva' => "\x{0936}",
+ 'shagujarati' => "\x{0AB6}",
+ 'shagurmukhi' => "\x{0A36}",
+ 'shalshelethebrew' => "\x{0593}",
+ 'shbopomofo' => "\x{3115}",
+ 'shchacyrillic' => "\x{0449}",
+ 'sheenarabic' => "\x{0634}",
+ 'sheenfinalarabic' => "\x{FEB6}",
+ 'sheeninitialarabic' => "\x{FEB7}",
+ 'sheenmedialarabic' => "\x{FEB8}",
+ 'sheicoptic' => "\x{03E3}",
+ 'sheqel' => "\x{20AA}",
+ 'sheqelhebrew' => "\x{20AA}",
+ 'sheva' => "\x{05B0}",
+ 'sheva115' => "\x{05B0}",
+ 'sheva15' => "\x{05B0}",
+ 'sheva22' => "\x{05B0}",
+ 'sheva2e' => "\x{05B0}",
+ 'shevahebrew' => "\x{05B0}",
+ 'shevanarrowhebrew' => "\x{05B0}",
+ 'shevaquarterhebrew' => "\x{05B0}",
+ 'shevawidehebrew' => "\x{05B0}",
+ 'shhacyrillic' => "\x{04BB}",
+ 'shimacoptic' => "\x{03ED}",
+ 'shin' => "\x{05E9}",
+ 'shindagesh' => "\x{FB49}",
+ 'shindageshhebrew' => "\x{FB49}",
+ 'shindageshshindot' => "\x{FB2C}",
+ 'shindageshshindothebrew' => "\x{FB2C}",
+ 'shindageshsindot' => "\x{FB2D}",
+ 'shindageshsindothebrew' => "\x{FB2D}",
+ 'shindothebrew' => "\x{05C1}",
+ 'shinhebrew' => "\x{05E9}",
+ 'shinshindot' => "\x{FB2A}",
+ 'shinshindothebrew' => "\x{FB2A}",
+ 'shinsindot' => "\x{FB2B}",
+ 'shinsindothebrew' => "\x{FB2B}",
+ 'shook' => "\x{0282}",
+ 'sigmafinal' => "\x{03C2}",
+ 'sigmalunatesymbolgreek' => "\x{03F2}",
+ 'sihiragana' => "\x{3057}",
+ 'sikatakana' => "\x{30B7}",
+ 'sikatakanahalfwidth' => "\x{FF7C}",
+ 'siluqhebrew' => "\x{05BD}",
+ 'siluqlefthebrew' => "\x{05BD}",
+ 'sindothebrew' => "\x{05C2}",
+ 'siosacirclekorean' => "\x{3274}",
+ 'siosaparenkorean' => "\x{3214}",
+ 'sioscieuckorean' => "\x{317E}",
+ 'sioscirclekorean' => "\x{3266}",
+ 'sioskiyeokkorean' => "\x{317A}",
+ 'sioskorean' => "\x{3145}",
+ 'siosnieunkorean' => "\x{317B}",
+ 'siosparenkorean' => "\x{3206}",
+ 'siospieupkorean' => "\x{317D}",
+ 'siostikeutkorean' => "\x{317C}",
+ 'sixarabic' => "\x{0666}",
+ 'sixbengali' => "\x{09EC}",
+ 'sixcircle' => "\x{2465}",
+ 'sixcircleinversesansserif' => "\x{278F}",
+ 'sixdeva' => "\x{096C}",
+ 'sixgujarati' => "\x{0AEC}",
+ 'sixgurmukhi' => "\x{0A6C}",
+ 'sixhackarabic' => "\x{0666}",
+ 'sixhangzhou' => "\x{3026}",
+ 'sixideographicparen' => "\x{3225}",
+ 'sixinferior' => "\x{2086}",
+ 'sixmonospace' => "\x{FF16}",
+ 'sixoldstyle' => "\x{F736}",
+ 'sixparen' => "\x{2479}",
+ 'sixperiod' => "\x{248D}",
+ 'sixpersian' => "\x{06F6}",
+ 'sixroman' => "\x{2175}",
+ 'sixsuperior' => "\x{2076}",
+ 'sixteencircle' => "\x{246F}",
+ 'sixteencurrencydenominatorbengali' => "\x{09F9}",
+ 'sixteenparen' => "\x{2483}",
+ 'sixteenperiod' => "\x{2497}",
+ 'sixthai' => "\x{0E56}",
+ 'slashmonospace' => "\x{FF0F}",
+ 'slong' => "\x{017F}",
+ 'slongdotaccent' => "\x{1E9B}",
+ 'smonospace' => "\x{FF53}",
+ 'sofpasuqhebrew' => "\x{05C3}",
+ 'softhyphen' => "\x{00AD}",
+ 'softsigncyrillic' => "\x{044C}",
+ 'sohiragana' => "\x{305D}",
+ 'sokatakana' => "\x{30BD}",
+ 'sokatakanahalfwidth' => "\x{FF7F}",
+ 'soliduslongoverlaycmb' => "\x{0338}",
+ 'solidusshortoverlaycmb' => "\x{0337}",
+ 'sorusithai' => "\x{0E29}",
+ 'sosalathai' => "\x{0E28}",
+ 'sosothai' => "\x{0E0B}",
+ 'sosuathai' => "\x{0E2A}",
+ 'spacehackarabic' => "\x{0020}",
+ 'spadesuitblack' => "\x{2660}",
+ 'spadesuitwhite' => "\x{2664}",
+ 'sparen' => "\x{24AE}",
+ 'squarebelowcmb' => "\x{033B}",
+ 'squarecc' => "\x{33C4}",
+ 'squarecm' => "\x{339D}",
+ 'squarediagonalcrosshatchfill' => "\x{25A9}",
+ 'squarehorizontalfill' => "\x{25A4}",
+ 'squarekg' => "\x{338F}",
+ 'squarekm' => "\x{339E}",
+ 'squarekmcapital' => "\x{33CE}",
+ 'squareln' => "\x{33D1}",
+ 'squarelog' => "\x{33D2}",
+ 'squaremg' => "\x{338E}",
+ 'squaremil' => "\x{33D5}",
+ 'squaremm' => "\x{339C}",
+ 'squaremsquared' => "\x{33A1}",
+ 'squareorthogonalcrosshatchfill' => "\x{25A6}",
+ 'squareupperlefttolowerrightfill' => "\x{25A7}",
+ 'squareupperrighttolowerleftfill' => "\x{25A8}",
+ 'squareverticalfill' => "\x{25A5}",
+ 'squarewhitewithsmallblack' => "\x{25A3}",
+ 'srsquare' => "\x{33DB}",
+ 'ssabengali' => "\x{09B7}",
+ 'ssadeva' => "\x{0937}",
+ 'ssagujarati' => "\x{0AB7}",
+ 'ssangcieuckorean' => "\x{3149}",
+ 'ssanghieuhkorean' => "\x{3185}",
+ 'ssangieungkorean' => "\x{3180}",
+ 'ssangkiyeokkorean' => "\x{3132}",
+ 'ssangnieunkorean' => "\x{3165}",
+ 'ssangpieupkorean' => "\x{3143}",
+ 'ssangsioskorean' => "\x{3146}",
+ 'ssangtikeutkorean' => "\x{3138}",
+ 'ssuperior' => "\x{F6F2}",
+ 'sterlingmonospace' => "\x{FFE1}",
+ 'strokelongoverlaycmb' => "\x{0336}",
+ 'strokeshortoverlaycmb' => "\x{0335}",
+ 'subset' => "\x{2282}",
+ 'subsetnotequal' => "\x{228A}",
+ 'subsetorequal' => "\x{2286}",
+ 'succeeds' => "\x{227B}",
+ 'suhiragana' => "\x{3059}",
+ 'sukatakana' => "\x{30B9}",
+ 'sukatakanahalfwidth' => "\x{FF7D}",
+ 'sukunarabic' => "\x{0652}",
+ 'superset' => "\x{2283}",
+ 'supersetnotequal' => "\x{228B}",
+ 'supersetorequal' => "\x{2287}",
+ 'svsquare' => "\x{33DC}",
+ 'syouwaerasquare' => "\x{337C}",
+ 'tabengali' => "\x{09A4}",
+ 'tackdown' => "\x{22A4}",
+ 'tackleft' => "\x{22A3}",
+ 'tadeva' => "\x{0924}",
+ 'tagujarati' => "\x{0AA4}",
+ 'tagurmukhi' => "\x{0A24}",
+ 'taharabic' => "\x{0637}",
+ 'tahfinalarabic' => "\x{FEC2}",
+ 'tahinitialarabic' => "\x{FEC3}",
+ 'tahiragana' => "\x{305F}",
+ 'tahmedialarabic' => "\x{FEC4}",
+ 'taisyouerasquare' => "\x{337D}",
+ 'takatakana' => "\x{30BF}",
+ 'takatakanahalfwidth' => "\x{FF80}",
+ 'tatweelarabic' => "\x{0640}",
+ 'tav' => "\x{05EA}",
+ 'tavdages' => "\x{FB4A}",
+ 'tavdagesh' => "\x{FB4A}",
+ 'tavdageshhebrew' => "\x{FB4A}",
+ 'tavhebrew' => "\x{05EA}",
+ 'tbopomofo' => "\x{310A}",
+ 'tccurl' => "\x{02A8}",
+ 'tcedilla' => "\x{0163}",
+ 'tcheharabic' => "\x{0686}",
+ 'tchehfinalarabic' => "\x{FB7B}",
+ 'tchehinitialarabic' => "\x{FB7C}",
+ 'tchehmedialarabic' => "\x{FB7D}",
+ 'tchehmeeminitialarabic' => "\x{FB7C}\x{FEE4}",
+ 'tcircle' => "\x{24E3}",
+ 'tcircumflexbelow' => "\x{1E71}",
+ 'tdieresis' => "\x{1E97}",
+ 'tdotaccent' => "\x{1E6B}",
+ 'tdotbelow' => "\x{1E6D}",
+ 'tecyrillic' => "\x{0442}",
+ 'tedescendercyrillic' => "\x{04AD}",
+ 'teharabic' => "\x{062A}",
+ 'tehfinalarabic' => "\x{FE96}",
+ 'tehhahinitialarabic' => "\x{FCA2}",
+ 'tehhahisolatedarabic' => "\x{FC0C}",
+ 'tehinitialarabic' => "\x{FE97}",
+ 'tehiragana' => "\x{3066}",
+ 'tehjeeminitialarabic' => "\x{FCA1}",
+ 'tehjeemisolatedarabic' => "\x{FC0B}",
+ 'tehmarbutaarabic' => "\x{0629}",
+ 'tehmarbutafinalarabic' => "\x{FE94}",
+ 'tehmedialarabic' => "\x{FE98}",
+ 'tehmeeminitialarabic' => "\x{FCA4}",
+ 'tehmeemisolatedarabic' => "\x{FC0E}",
+ 'tehnoonfinalarabic' => "\x{FC73}",
+ 'tekatakana' => "\x{30C6}",
+ 'tekatakanahalfwidth' => "\x{FF83}",
+ 'telephone' => "\x{2121}",
+ 'telephoneblack' => "\x{260E}",
+ 'telishagedolahebrew' => "\x{05A0}",
+ 'telishaqetanahebrew' => "\x{05A9}",
+ 'tencircle' => "\x{2469}",
+ 'tenideographicparen' => "\x{3229}",
+ 'tenparen' => "\x{247D}",
+ 'tenperiod' => "\x{2491}",
+ 'tenroman' => "\x{2179}",
+ 'tesh' => "\x{02A7}",
+ 'tet' => "\x{05D8}",
+ 'tetdagesh' => "\x{FB38}",
+ 'tetdageshhebrew' => "\x{FB38}",
+ 'tethebrew' => "\x{05D8}",
+ 'tetsecyrillic' => "\x{04B5}",
+ 'tevirhebrew' => "\x{059B}",
+ 'tevirlefthebrew' => "\x{059B}",
+ 'thabengali' => "\x{09A5}",
+ 'thadeva' => "\x{0925}",
+ 'thagujarati' => "\x{0AA5}",
+ 'thagurmukhi' => "\x{0A25}",
+ 'thalarabic' => "\x{0630}",
+ 'thalfinalarabic' => "\x{FEAC}",
+ 'thanthakhatlowleftthai' => "\x{F898}",
+ 'thanthakhatlowrightthai' => "\x{F897}",
+ 'thanthakhatthai' => "\x{0E4C}",
+ 'thanthakhatupperleftthai' => "\x{F896}",
+ 'theharabic' => "\x{062B}",
+ 'thehfinalarabic' => "\x{FE9A}",
+ 'thehinitialarabic' => "\x{FE9B}",
+ 'thehmedialarabic' => "\x{FE9C}",
+ 'thereexists' => "\x{2203}",
+ 'thetasymbolgreek' => "\x{03D1}",
+ 'thieuthacirclekorean' => "\x{3279}",
+ 'thieuthaparenkorean' => "\x{3219}",
+ 'thieuthcirclekorean' => "\x{326B}",
+ 'thieuthkorean' => "\x{314C}",
+ 'thieuthparenkorean' => "\x{320B}",
+ 'thirteencircle' => "\x{246C}",
+ 'thirteenparen' => "\x{2480}",
+ 'thirteenperiod' => "\x{2494}",
+ 'thonangmonthothai' => "\x{0E11}",
+ 'thook' => "\x{01AD}",
+ 'thophuthaothai' => "\x{0E12}",
+ 'thothahanthai' => "\x{0E17}",
+ 'thothanthai' => "\x{0E10}",
+ 'thothongthai' => "\x{0E18}",
+ 'thothungthai' => "\x{0E16}",
+ 'thousandcyrillic' => "\x{0482}",
+ 'thousandsseparatorarabic' => "\x{066C}",
+ 'thousandsseparatorpersian' => "\x{066C}",
+ 'threearabic' => "\x{0663}",
+ 'threebengali' => "\x{09E9}",
+ 'threecircle' => "\x{2462}",
+ 'threecircleinversesansserif' => "\x{278C}",
+ 'threedeva' => "\x{0969}",
+ 'threegujarati' => "\x{0AE9}",
+ 'threegurmukhi' => "\x{0A69}",
+ 'threehackarabic' => "\x{0663}",
+ 'threehangzhou' => "\x{3023}",
+ 'threeideographicparen' => "\x{3222}",
+ 'threeinferior' => "\x{2083}",
+ 'threemonospace' => "\x{FF13}",
+ 'threenumeratorbengali' => "\x{09F6}",
+ 'threeoldstyle' => "\x{F733}",
+ 'threeparen' => "\x{2476}",
+ 'threeperiod' => "\x{248A}",
+ 'threepersian' => "\x{06F3}",
+ 'threequartersemdash' => "\x{F6DE}",
+ 'threeroman' => "\x{2172}",
+ 'threethai' => "\x{0E53}",
+ 'thzsquare' => "\x{3394}",
+ 'tihiragana' => "\x{3061}",
+ 'tikatakana' => "\x{30C1}",
+ 'tikatakanahalfwidth' => "\x{FF81}",
+ 'tikeutacirclekorean' => "\x{3270}",
+ 'tikeutaparenkorean' => "\x{3210}",
+ 'tikeutcirclekorean' => "\x{3262}",
+ 'tikeutkorean' => "\x{3137}",
+ 'tikeutparenkorean' => "\x{3202}",
+ 'tildebelowcmb' => "\x{0330}",
+ 'tildecmb' => "\x{0303}",
+ 'tildedoublecmb' => "\x{0360}",
+ 'tildeoperator' => "\x{223C}",
+ 'tildeoverlaycmb' => "\x{0334}",
+ 'tildeverticalcmb' => "\x{033E}",
+ 'timescircle' => "\x{2297}",
+ 'tipehahebrew' => "\x{0596}",
+ 'tipehalefthebrew' => "\x{0596}",
+ 'tippigurmukhi' => "\x{0A70}",
+ 'titlocyrilliccmb' => "\x{0483}",
+ 'tiwnarmenian' => "\x{057F}",
+ 'tlinebelow' => "\x{1E6F}",
+ 'tmonospace' => "\x{FF54}",
+ 'toarmenian' => "\x{0569}",
+ 'tohiragana' => "\x{3068}",
+ 'tokatakana' => "\x{30C8}",
+ 'tokatakanahalfwidth' => "\x{FF84}",
+ 'tonebarextrahighmod' => "\x{02E5}",
+ 'tonebarextralowmod' => "\x{02E9}",
+ 'tonebarhighmod' => "\x{02E6}",
+ 'tonebarlowmod' => "\x{02E8}",
+ 'tonebarmidmod' => "\x{02E7}",
+ 'tonefive' => "\x{01BD}",
+ 'tonesix' => "\x{0185}",
+ 'tonetwo' => "\x{01A8}",
+ 'tonsquare' => "\x{3327}",
+ 'topatakthai' => "\x{0E0F}",
+ 'tortoiseshellbracketleft' => "\x{3014}",
+ 'tortoiseshellbracketleftsmall' => "\x{FE5D}",
+ 'tortoiseshellbracketleftvertical' => "\x{FE39}",
+ 'tortoiseshellbracketright' => "\x{3015}",
+ 'tortoiseshellbracketrightsmall' => "\x{FE5E}",
+ 'tortoiseshellbracketrightvertical' => "\x{FE3A}",
+ 'totaothai' => "\x{0E15}",
+ 'tpalatalhook' => "\x{01AB}",
+ 'tparen' => "\x{24AF}",
+ 'trademarksans' => "\x{F8EA}",
+ 'trademarkserif' => "\x{F6DB}",
+ 'tretroflexhook' => "\x{0288}",
+ 'ts' => "\x{02A6}",
+ 'tsadi' => "\x{05E6}",
+ 'tsadidagesh' => "\x{FB46}",
+ 'tsadidageshhebrew' => "\x{FB46}",
+ 'tsadihebrew' => "\x{05E6}",
+ 'tsecyrillic' => "\x{0446}",
+ 'tsere' => "\x{05B5}",
+ 'tsere12' => "\x{05B5}",
+ 'tsere1e' => "\x{05B5}",
+ 'tsere2b' => "\x{05B5}",
+ 'tserehebrew' => "\x{05B5}",
+ 'tserenarrowhebrew' => "\x{05B5}",
+ 'tserequarterhebrew' => "\x{05B5}",
+ 'tserewidehebrew' => "\x{05B5}",
+ 'tshecyrillic' => "\x{045B}",
+ 'tsuperior' => "\x{F6F3}",
+ 'ttabengali' => "\x{099F}",
+ 'ttadeva' => "\x{091F}",
+ 'ttagujarati' => "\x{0A9F}",
+ 'ttagurmukhi' => "\x{0A1F}",
+ 'tteharabic' => "\x{0679}",
+ 'ttehfinalarabic' => "\x{FB67}",
+ 'ttehinitialarabic' => "\x{FB68}",
+ 'ttehmedialarabic' => "\x{FB69}",
+ 'tthabengali' => "\x{09A0}",
+ 'tthadeva' => "\x{0920}",
+ 'tthagujarati' => "\x{0AA0}",
+ 'tthagurmukhi' => "\x{0A20}",
+ 'tturned' => "\x{0287}",
+ 'tuhiragana' => "\x{3064}",
+ 'tukatakana' => "\x{30C4}",
+ 'tukatakanahalfwidth' => "\x{FF82}",
+ 'tusmallhiragana' => "\x{3063}",
+ 'tusmallkatakana' => "\x{30C3}",
+ 'tusmallkatakanahalfwidth' => "\x{FF6F}",
+ 'twelvecircle' => "\x{246B}",
+ 'twelveparen' => "\x{247F}",
+ 'twelveperiod' => "\x{2493}",
+ 'twelveroman' => "\x{217B}",
+ 'twentycircle' => "\x{2473}",
+ 'twentyhangzhou' => "\x{5344}",
+ 'twentyparen' => "\x{2487}",
+ 'twentyperiod' => "\x{249B}",
+ 'twoarabic' => "\x{0662}",
+ 'twobengali' => "\x{09E8}",
+ 'twocircle' => "\x{2461}",
+ 'twocircleinversesansserif' => "\x{278B}",
+ 'twodeva' => "\x{0968}",
+ 'twodotleader' => "\x{2025}",
+ 'twodotleadervertical' => "\x{FE30}",
+ 'twogujarati' => "\x{0AE8}",
+ 'twogurmukhi' => "\x{0A68}",
+ 'twohackarabic' => "\x{0662}",
+ 'twohangzhou' => "\x{3022}",
+ 'twoideographicparen' => "\x{3221}",
+ 'twoinferior' => "\x{2082}",
+ 'twomonospace' => "\x{FF12}",
+ 'twonumeratorbengali' => "\x{09F5}",
+ 'twooldstyle' => "\x{F732}",
+ 'twoparen' => "\x{2475}",
+ 'twoperiod' => "\x{2489}",
+ 'twopersian' => "\x{06F2}",
+ 'tworoman' => "\x{2171}",
+ 'twostroke' => "\x{01BB}",
+ 'twothai' => "\x{0E52}",
+ 'ubar' => "\x{0289}",
+ 'ubengali' => "\x{0989}",
+ 'ubopomofo' => "\x{3128}",
+ 'ucaron' => "\x{01D4}",
+ 'ucircle' => "\x{24E4}",
+ 'ucircumflexbelow' => "\x{1E77}",
+ 'ucyrillic' => "\x{0443}",
+ 'udattadeva' => "\x{0951}",
+ 'udblacute' => "\x{0171}",
+ 'udblgrave' => "\x{0215}",
+ 'udeva' => "\x{0909}",
+ 'udieresisacute' => "\x{01D8}",
+ 'udieresisbelow' => "\x{1E73}",
+ 'udieresiscaron' => "\x{01DA}",
+ 'udieresiscyrillic' => "\x{04F1}",
+ 'udieresisgrave' => "\x{01DC}",
+ 'udieresismacron' => "\x{01D6}",
+ 'udotbelow' => "\x{1EE5}",
+ 'ugujarati' => "\x{0A89}",
+ 'ugurmukhi' => "\x{0A09}",
+ 'uhiragana' => "\x{3046}",
+ 'uhookabove' => "\x{1EE7}",
+ 'uhornacute' => "\x{1EE9}",
+ 'uhorndotbelow' => "\x{1EF1}",
+ 'uhorngrave' => "\x{1EEB}",
+ 'uhornhookabove' => "\x{1EED}",
+ 'uhorntilde' => "\x{1EEF}",
+ 'uhungarumlautcyrillic' => "\x{04F3}",
+ 'uinvertedbreve' => "\x{0217}",
+ 'ukatakana' => "\x{30A6}",
+ 'ukatakanahalfwidth' => "\x{FF73}",
+ 'ukcyrillic' => "\x{0479}",
+ 'ukorean' => "\x{315C}",
+ 'umacroncyrillic' => "\x{04EF}",
+ 'umacrondieresis' => "\x{1E7B}",
+ 'umatragurmukhi' => "\x{0A41}",
+ 'umonospace' => "\x{FF55}",
+ 'underscoremonospace' => "\x{FF3F}",
+ 'underscorevertical' => "\x{FE33}",
+ 'underscorewavy' => "\x{FE4F}",
+ 'uparen' => "\x{24B0}",
+ 'upperdothebrew' => "\x{05C4}",
+ 'upsilonlatin' => "\x{028A}",
+ 'uptackbelowcmb' => "\x{031D}",
+ 'uptackmod' => "\x{02D4}",
+ 'uragurmukhi' => "\x{0A73}",
+ 'ushortcyrillic' => "\x{045E}",
+ 'usmallhiragana' => "\x{3045}",
+ 'usmallkatakana' => "\x{30A5}",
+ 'usmallkatakanahalfwidth' => "\x{FF69}",
+ 'ustraightcyrillic' => "\x{04AF}",
+ 'ustraightstrokecyrillic' => "\x{04B1}",
+ 'utildeacute' => "\x{1E79}",
+ 'utildebelow' => "\x{1E75}",
+ 'uubengali' => "\x{098A}",
+ 'uudeva' => "\x{090A}",
+ 'uugujarati' => "\x{0A8A}",
+ 'uugurmukhi' => "\x{0A0A}",
+ 'uumatragurmukhi' => "\x{0A42}",
+ 'uuvowelsignbengali' => "\x{09C2}",
+ 'uuvowelsigndeva' => "\x{0942}",
+ 'uuvowelsigngujarati' => "\x{0AC2}",
+ 'uvowelsignbengali' => "\x{09C1}",
+ 'uvowelsigndeva' => "\x{0941}",
+ 'uvowelsigngujarati' => "\x{0AC1}",
+ 'vadeva' => "\x{0935}",
+ 'vagujarati' => "\x{0AB5}",
+ 'vagurmukhi' => "\x{0A35}",
+ 'vakatakana' => "\x{30F7}",
+ 'vav' => "\x{05D5}",
+ 'vavdagesh' => "\x{FB35}",
+ 'vavdagesh65' => "\x{FB35}",
+ 'vavdageshhebrew' => "\x{FB35}",
+ 'vavhebrew' => "\x{05D5}",
+ 'vavholam' => "\x{FB4B}",
+ 'vavholamhebrew' => "\x{FB4B}",
+ 'vavvavhebrew' => "\x{05F0}",
+ 'vavyodhebrew' => "\x{05F1}",
+ 'vcircle' => "\x{24E5}",
+ 'vdotbelow' => "\x{1E7F}",
+ 'vecyrillic' => "\x{0432}",
+ 'veharabic' => "\x{06A4}",
+ 'vehfinalarabic' => "\x{FB6B}",
+ 'vehinitialarabic' => "\x{FB6C}",
+ 'vehmedialarabic' => "\x{FB6D}",
+ 'vekatakana' => "\x{30F9}",
+ 'venus' => "\x{2640}",
+ 'verticalbar' => "\x{007C}",
+ 'verticallineabovecmb' => "\x{030D}",
+ 'verticallinebelowcmb' => "\x{0329}",
+ 'verticallinelowmod' => "\x{02CC}",
+ 'verticallinemod' => "\x{02C8}",
+ 'vewarmenian' => "\x{057E}",
+ 'vhook' => "\x{028B}",
+ 'vikatakana' => "\x{30F8}",
+ 'viramabengali' => "\x{09CD}",
+ 'viramadeva' => "\x{094D}",
+ 'viramagujarati' => "\x{0ACD}",
+ 'visargabengali' => "\x{0983}",
+ 'visargadeva' => "\x{0903}",
+ 'visargagujarati' => "\x{0A83}",
+ 'vmonospace' => "\x{FF56}",
+ 'voarmenian' => "\x{0578}",
+ 'voicediterationhiragana' => "\x{309E}",
+ 'voicediterationkatakana' => "\x{30FE}",
+ 'voicedmarkkana' => "\x{309B}",
+ 'voicedmarkkanahalfwidth' => "\x{FF9E}",
+ 'vokatakana' => "\x{30FA}",
+ 'vparen' => "\x{24B1}",
+ 'vtilde' => "\x{1E7D}",
+ 'vturned' => "\x{028C}",
+ 'vuhiragana' => "\x{3094}",
+ 'vukatakana' => "\x{30F4}",
+ 'waekorean' => "\x{3159}",
+ 'wahiragana' => "\x{308F}",
+ 'wakatakana' => "\x{30EF}",
+ 'wakatakanahalfwidth' => "\x{FF9C}",
+ 'wakorean' => "\x{3158}",
+ 'wasmallhiragana' => "\x{308E}",
+ 'wasmallkatakana' => "\x{30EE}",
+ 'wattosquare' => "\x{3357}",
+ 'wavedash' => "\x{301C}",
+ 'wavyunderscorevertical' => "\x{FE34}",
+ 'wawarabic' => "\x{0648}",
+ 'wawfinalarabic' => "\x{FEEE}",
+ 'wawhamzaabovearabic' => "\x{0624}",
+ 'wawhamzaabovefinalarabic' => "\x{FE86}",
+ 'wbsquare' => "\x{33DD}",
+ 'wcircle' => "\x{24E6}",
+ 'wdotaccent' => "\x{1E87}",
+ 'wdotbelow' => "\x{1E89}",
+ 'wehiragana' => "\x{3091}",
+ 'wekatakana' => "\x{30F1}",
+ 'wekorean' => "\x{315E}",
+ 'weokorean' => "\x{315D}",
+ 'whitebullet' => "\x{25E6}",
+ 'whitecircle' => "\x{25CB}",
+ 'whitecircleinverse' => "\x{25D9}",
+ 'whitecornerbracketleft' => "\x{300E}",
+ 'whitecornerbracketleftvertical' => "\x{FE43}",
+ 'whitecornerbracketright' => "\x{300F}",
+ 'whitecornerbracketrightvertical' => "\x{FE44}",
+ 'whitediamond' => "\x{25C7}",
+ 'whitediamondcontainingblacksmalldiamond' => "\x{25C8}",
+ 'whitedownpointingsmalltriangle' => "\x{25BF}",
+ 'whitedownpointingtriangle' => "\x{25BD}",
+ 'whiteleftpointingsmalltriangle' => "\x{25C3}",
+ 'whiteleftpointingtriangle' => "\x{25C1}",
+ 'whitelenticularbracketleft' => "\x{3016}",
+ 'whitelenticularbracketright' => "\x{3017}",
+ 'whiterightpointingsmalltriangle' => "\x{25B9}",
+ 'whiterightpointingtriangle' => "\x{25B7}",
+ 'whitesmallsquare' => "\x{25AB}",
+ 'whitesmilingface' => "\x{263A}",
+ 'whitesquare' => "\x{25A1}",
+ 'whitestar' => "\x{2606}",
+ 'whitetelephone' => "\x{260F}",
+ 'whitetortoiseshellbracketleft' => "\x{3018}",
+ 'whitetortoiseshellbracketright' => "\x{3019}",
+ 'whiteuppointingsmalltriangle' => "\x{25B5}",
+ 'whiteuppointingtriangle' => "\x{25B3}",
+ 'wihiragana' => "\x{3090}",
+ 'wikatakana' => "\x{30F0}",
+ 'wikorean' => "\x{315F}",
+ 'wmonospace' => "\x{FF57}",
+ 'wohiragana' => "\x{3092}",
+ 'wokatakana' => "\x{30F2}",
+ 'wokatakanahalfwidth' => "\x{FF66}",
+ 'won' => "\x{20A9}",
+ 'wonmonospace' => "\x{FFE6}",
+ 'wowaenthai' => "\x{0E27}",
+ 'wparen' => "\x{24B2}",
+ 'wring' => "\x{1E98}",
+ 'wsuperior' => "\x{02B7}",
+ 'wturned' => "\x{028D}",
+ 'wynn' => "\x{01BF}",
+ 'xabovecmb' => "\x{033D}",
+ 'xbopomofo' => "\x{3112}",
+ 'xcircle' => "\x{24E7}",
+ 'xdieresis' => "\x{1E8D}",
+ 'xdotaccent' => "\x{1E8B}",
+ 'xeharmenian' => "\x{056D}",
+ 'xmonospace' => "\x{FF58}",
+ 'xparen' => "\x{24B3}",
+ 'xsuperior' => "\x{02E3}",
+ 'yaadosquare' => "\x{334E}",
+ 'yabengali' => "\x{09AF}",
+ 'yadeva' => "\x{092F}",
+ 'yaekorean' => "\x{3152}",
+ 'yagujarati' => "\x{0AAF}",
+ 'yagurmukhi' => "\x{0A2F}",
+ 'yahiragana' => "\x{3084}",
+ 'yakatakana' => "\x{30E4}",
+ 'yakatakanahalfwidth' => "\x{FF94}",
+ 'yakorean' => "\x{3151}",
+ 'yamakkanthai' => "\x{0E4E}",
+ 'yasmallhiragana' => "\x{3083}",
+ 'yasmallkatakana' => "\x{30E3}",
+ 'yasmallkatakanahalfwidth' => "\x{FF6C}",
+ 'yatcyrillic' => "\x{0463}",
+ 'ycircle' => "\x{24E8}",
+ 'ydotaccent' => "\x{1E8F}",
+ 'ydotbelow' => "\x{1EF5}",
+ 'yeharabic' => "\x{064A}",
+ 'yehbarreearabic' => "\x{06D2}",
+ 'yehbarreefinalarabic' => "\x{FBAF}",
+ 'yehfinalarabic' => "\x{FEF2}",
+ 'yehhamzaabovearabic' => "\x{0626}",
+ 'yehhamzaabovefinalarabic' => "\x{FE8A}",
+ 'yehhamzaaboveinitialarabic' => "\x{FE8B}",
+ 'yehhamzaabovemedialarabic' => "\x{FE8C}",
+ 'yehinitialarabic' => "\x{FEF3}",
+ 'yehmedialarabic' => "\x{FEF4}",
+ 'yehmeeminitialarabic' => "\x{FCDD}",
+ 'yehmeemisolatedarabic' => "\x{FC58}",
+ 'yehnoonfinalarabic' => "\x{FC94}",
+ 'yehthreedotsbelowarabic' => "\x{06D1}",
+ 'yekorean' => "\x{3156}",
+ 'yenmonospace' => "\x{FFE5}",
+ 'yeokorean' => "\x{3155}",
+ 'yeorinhieuhkorean' => "\x{3186}",
+ 'yerahbenyomohebrew' => "\x{05AA}",
+ 'yerahbenyomolefthebrew' => "\x{05AA}",
+ 'yericyrillic' => "\x{044B}",
+ 'yerudieresiscyrillic' => "\x{04F9}",
+ 'yesieungkorean' => "\x{3181}",
+ 'yesieungpansioskorean' => "\x{3183}",
+ 'yesieungsioskorean' => "\x{3182}",
+ 'yetivhebrew' => "\x{059A}",
+ 'yhook' => "\x{01B4}",
+ 'yhookabove' => "\x{1EF7}",
+ 'yiarmenian' => "\x{0575}",
+ 'yicyrillic' => "\x{0457}",
+ 'yikorean' => "\x{3162}",
+ 'yinyang' => "\x{262F}",
+ 'yiwnarmenian' => "\x{0582}",
+ 'ymonospace' => "\x{FF59}",
+ 'yod' => "\x{05D9}",
+ 'yoddagesh' => "\x{FB39}",
+ 'yoddageshhebrew' => "\x{FB39}",
+ 'yodhebrew' => "\x{05D9}",
+ 'yodyodhebrew' => "\x{05F2}",
+ 'yodyodpatahhebrew' => "\x{FB1F}",
+ 'yohiragana' => "\x{3088}",
+ 'yoikorean' => "\x{3189}",
+ 'yokatakana' => "\x{30E8}",
+ 'yokatakanahalfwidth' => "\x{FF96}",
+ 'yokorean' => "\x{315B}",
+ 'yosmallhiragana' => "\x{3087}",
+ 'yosmallkatakana' => "\x{30E7}",
+ 'yosmallkatakanahalfwidth' => "\x{FF6E}",
+ 'yotgreek' => "\x{03F3}",
+ 'yoyaekorean' => "\x{3188}",
+ 'yoyakorean' => "\x{3187}",
+ 'yoyakthai' => "\x{0E22}",
+ 'yoyingthai' => "\x{0E0D}",
+ 'yparen' => "\x{24B4}",
+ 'ypogegrammeni' => "\x{037A}",
+ 'ypogegrammenigreekcmb' => "\x{0345}",
+ 'yr' => "\x{01A6}",
+ 'yring' => "\x{1E99}",
+ 'ysuperior' => "\x{02B8}",
+ 'ytilde' => "\x{1EF9}",
+ 'yturned' => "\x{028E}",
+ 'yuhiragana' => "\x{3086}",
+ 'yuikorean' => "\x{318C}",
+ 'yukatakana' => "\x{30E6}",
+ 'yukatakanahalfwidth' => "\x{FF95}",
+ 'yukorean' => "\x{3160}",
+ 'yusbigcyrillic' => "\x{046B}",
+ 'yusbigiotifiedcyrillic' => "\x{046D}",
+ 'yuslittlecyrillic' => "\x{0467}",
+ 'yuslittleiotifiedcyrillic' => "\x{0469}",
+ 'yusmallhiragana' => "\x{3085}",
+ 'yusmallkatakana' => "\x{30E5}",
+ 'yusmallkatakanahalfwidth' => "\x{FF6D}",
+ 'yuyekorean' => "\x{318B}",
+ 'yuyeokorean' => "\x{318A}",
+ 'yyabengali' => "\x{09DF}",
+ 'yyadeva' => "\x{095F}",
+ 'zaarmenian' => "\x{0566}",
+ 'zadeva' => "\x{095B}",
+ 'zagurmukhi' => "\x{0A5B}",
+ 'zaharabic' => "\x{0638}",
+ 'zahfinalarabic' => "\x{FEC6}",
+ 'zahinitialarabic' => "\x{FEC7}",
+ 'zahiragana' => "\x{3056}",
+ 'zahmedialarabic' => "\x{FEC8}",
+ 'zainarabic' => "\x{0632}",
+ 'zainfinalarabic' => "\x{FEB0}",
+ 'zakatakana' => "\x{30B6}",
+ 'zaqefgadolhebrew' => "\x{0595}",
+ 'zaqefqatanhebrew' => "\x{0594}",
+ 'zarqahebrew' => "\x{0598}",
+ 'zayin' => "\x{05D6}",
+ 'zayindagesh' => "\x{FB36}",
+ 'zayindageshhebrew' => "\x{FB36}",
+ 'zayinhebrew' => "\x{05D6}",
+ 'zbopomofo' => "\x{3117}",
+ 'zcircle' => "\x{24E9}",
+ 'zcircumflex' => "\x{1E91}",
+ 'zcurl' => "\x{0291}",
+ 'zdot' => "\x{017C}",
+ 'zdotbelow' => "\x{1E93}",
+ 'zecyrillic' => "\x{0437}",
+ 'zedescendercyrillic' => "\x{0499}",
+ 'zedieresiscyrillic' => "\x{04DF}",
+ 'zehiragana' => "\x{305C}",
+ 'zekatakana' => "\x{30BC}",
+ 'zeroarabic' => "\x{0660}",
+ 'zerobengali' => "\x{09E6}",
+ 'zerodeva' => "\x{0966}",
+ 'zerogujarati' => "\x{0AE6}",
+ 'zerogurmukhi' => "\x{0A66}",
+ 'zerohackarabic' => "\x{0660}",
+ 'zeroinferior' => "\x{2080}",
+ 'zeromonospace' => "\x{FF10}",
+ 'zerooldstyle' => "\x{F730}",
+ 'zeropersian' => "\x{06F0}",
+ 'zerosuperior' => "\x{2070}",
+ 'zerothai' => "\x{0E50}",
+ 'zerowidthjoiner' => "\x{FEFF}",
+ 'zerowidthnonjoiner' => "\x{200C}",
+ 'zerowidthspace' => "\x{200B}",
+ 'zhbopomofo' => "\x{3113}",
+ 'zhearmenian' => "\x{056A}",
+ 'zhebrevecyrillic' => "\x{04C2}",
+ 'zhecyrillic' => "\x{0436}",
+ 'zhedescendercyrillic' => "\x{0497}",
+ 'zhedieresiscyrillic' => "\x{04DD}",
+ 'zihiragana' => "\x{3058}",
+ 'zikatakana' => "\x{30B8}",
+ 'zinorhebrew' => "\x{05AE}",
+ 'zlinebelow' => "\x{1E95}",
+ 'zmonospace' => "\x{FF5A}",
+ 'zohiragana' => "\x{305E}",
+ 'zokatakana' => "\x{30BE}",
+ 'zparen' => "\x{24B5}",
+ 'zretroflexhook' => "\x{0290}",
+ 'zstroke' => "\x{01B6}",
+ 'zuhiragana' => "\x{305A}",
+ 'zukatakana' => "\x{30BA}",
+ );
+
+# Add to this list the glyphs for new fonts (from aglfn13):
+
+map { $agl{$names{$_}} = pack('U',hex ($_))} (keys %names);
+
+
+# %doubles = (map{$_ => "uni$_"} qw(0394 03A9 0162 2215 00AD 02C9 03BC 2219 00A0 0163));
+
+=head2 lookup ( $usv [, $noAlt [, $noUni] ])
+
+return the Adobe-recommended glyph name for a specific Unicode codepoint (integer). By default
+returns C<uniXXXX> names rather than C<afiiNNNNN> or C<SFnnnnnn> names
+
+If C<$noAlt> is true, C<afii> and C<SF> names are returned rather than C<uniXXXX>.
+
+if C<$noUni> is true, returns undef if it would have to resort to C<uniXXXX> or C<uXXXXXX>
+style names. Essentially this represents a straight lookup in the Adobe-recommended list.
+
+=cut
+
+sub lookup
+{
+ my ($num, $noalt, $noUni) = @_;
+ my ($val) = sprintf("%04X", $num);
+
+ if (defined $names{$val})
+ {
+ return $names{$val} if ($noalt || $names{$val} !~ m/^(?:afii|SF)/o);
+ }
+ return undef if $noUni;
+ if ($num > 0xFFFF)
+ { return "u$val"; }
+ elsif ($num)
+ { return "uni$val"; }
+ else
+ { return ".notdef"; }
+}
+
+=head2 parse ( $glyphname )
+
+Parse an Adobe-conformant glyph name, generating a Unicode codepoint sequence equivalent to the glyph (or
+glyph components, should the name represent a ligature). In scalar context, returns a reference to an
+array of Unicodes (decimal). Array is empty if the glyph name is non-conformant.
+In list context, the first item returned is the same array reference as above. The second item
+is a reference to an array containing the extensions (if any) present on the glyph name.
+The '.' that precedes each extension is not included.
+
+=cut
+
+sub parse
+{
+ my ($gname, @USVs, @extensions);
+ ($gname, @extensions) = split('\.', $_[0]);
+ # if name originally started with . (e.g., .null) then $gname will now be '' ... need to fix that up:
+ $gname = '.' . shift(@extensions) if $gname eq '';
+ if (defined $gname)
+ {
+ foreach $gname (split('_', $gname))
+ {
+ if ($gname =~ /^u[0-9a-fA-F]{4,6}$/)
+ {
+ push @USVs, hex(substr($gname, 1));
+ }
+ elsif ($gname =~ /^uni([0-9a-fA-F]{4,4})+$/)
+ {
+ push @USVs, map {hex($_)} ($gname =~ /([0-9a-fA-F]{4,4})/g)
+ }
+ elsif (exists $agl{$gname})
+ {
+ push @USVs, unpack ('U*', $agl{$gname});
+ }
+ }
+ }
+ return \@USVs unless wantarray;
+ my @res = (\@USVs, \@extensions);
+ return @res;
+}
+
+#Code used to parse Adobe's agl file and generate text for %agl initialization:
+#while (<ARGV>) {
+# chomp;
+# next if m/^#/;
+# my ($gname, @nums) = split(/[; ]/);
+# if ($#nums > 0 or !defined ($Font::TTF::PSNames::names{$nums[0]}) or $Font::TTF::PSNames::names{$nums[0]} ne $gname)
+# {
+# print "\t'$gname' => \"";
+# map {print "\\x{$_}" } @nums;
+# print "\",\n";
+# }
+# }
+
+=head1 AUTHOR
+
+Martin Hosken Martin_Hosken at sil.org. See L<Font::TTF::Font> for copyright and
+licensing.
+
+=cut
+
+1;
Modified: packages/libfont-ttf-perl/trunk/lib/Font/TTF/Post.pm
===================================================================
--- packages/libfont-ttf-perl/trunk/lib/Font/TTF/Post.pm 2006-01-17 02:56:43 UTC (rev 1966)
+++ packages/libfont-ttf-perl/trunk/lib/Font/TTF/Post.pm 2006-01-17 03:07:20 UTC (rev 1967)
@@ -1,305 +1,305 @@
-package Font::TTF::Post;
-
-=head1 NAME
-
-Font::TTF::Post - Holds the Postscript names for each glyph
-
-=head1 DESCRIPTION
-
-Holds the postscript names for glyphs. Note that they are not held as an
-array, but as indexes into two lists. The first list is the standard Postscript
-name list defined by the TrueType standard. The second comes from the font
-directly.
-
-Looking up a glyph from a Postscript name or a name from a glyph number is
-achieved through methods rather than variable lookup.
-
-This class handles PostScript table types of 1, 2, 2.5 & 3, but not version 4.
-Support for version 2.5 is as per Apple spec rather than MS.
-
-The way to look up Postscript names or glyphs is:
-
- $pname = $f->{'post'}{'VAL'}[$gnum];
- $gnum = $f->{'post'}{'STRINGS'}{$pname};
-
-=head1 INSTANCE VARIABLES
-
-Due to different systems having different limitations, there are various class
-variables available to control what post table types can be written.
-
-=over 4
-
-=item $Font::TTF::Post::no25
-
-If set tells Font::TTF::Post::out to use table type 2 instead of 2.5 in case apps
-can't handle version 2.5.
-
-=item VAL
-
-Contains an array indexed by glyph number of Postscript names. This is used when
-writing out a font.
-
-=item STRINGS
-
-An associative array of Postscript names mapping to the highest glyph with that
-name. These may not be in sync with VAL.
-
-=back
-
-In addition there are the standard introductory variables defined in the
-standard:
-
- FormatType
- italicAngle
- underlinePosition
- underlineThickness
- isFixedPitch
- minMemType42
- maxMemType42
- minMemType1
- maxMemType1
-
-=head1 METHODS
-
-=cut
-
-use strict;
-use vars qw(@ISA @base_set %base_set %fields $VERSION $no25 @field_info @base_set);
-require Font::TTF::Table;
-use Font::TTF::Utils;
-
-$no25 = 1; # officially deprecated format 2.5 tables in MS spec 1.3
-
- at ISA = qw(Font::TTF::Table);
- at field_info = (
- 'FormatType' => 'f',
- 'italicAngle' => 'f',
- 'underlinePosition' => 's',
- 'underlineThickness' => 's',
- 'isFixedPitch' => 'L',
- 'minMemType42' => 'L',
- 'maxMemType42' => 'L',
- 'minMemType1' => 'L',
- 'maxMemType1' => 'L');
- at base_set = qw(.notdef .null nonmarkingreturn space exclam quotedbl numbersign dollar percent ampersand quotesingle
- parenleft parenright asterisk plus comma hyphen period slash zero one two three four five six
- seven eight nine colon semicolon less equal greater question at A B C D E F G H I J K L M N O P Q
- R S T U V W X Y Z bracketleft backslash bracketright asciicircum underscore grave a b c d e f g h
- i j k l m n o p q r s t u v w x y z braceleft bar braceright asciitilde Adieresis Aring Ccedilla
- Eacute Ntilde Odieresis Udieresis aacute agrave acircumflex adieresis atilde aring ccedilla eacute
- egrave ecircumflex edieresis iacute igrave icircumflex idieresis ntilde oacute ograve ocircumflex
- odieresis otilde uacute ugrave ucircumflex udieresis dagger degree cent sterling section bullet
- paragraph germandbls registered copyright trademark acute dieresis notequal AE Oslash infinity
- plusminus lessequal greaterequal yen mu partialdiff summation product pi integral ordfeminine
- ordmasculine Omega ae oslash questiondown exclamdown logicalnot radical florin approxequal
- Delta guillemotleft guillemotright ellipsis nonbreakingspace Agrave Atilde Otilde OE oe endash emdash
- quotedblleft quotedblright quoteleft quoteright divide lozenge ydieresis Ydieresis fraction currency
- guilsinglleft guilsinglright fi fl daggerdbl periodcentered quotesinglbase quotedblbase perthousand
- Acircumflex Ecircumflex Aacute Edieresis Egrave Iacute Icircumflex Idieresis Igrave Oacute Ocircumflex
- apple Ograve Uacute Ucircumflex Ugrave dotlessi circumflex tilde macron breve dotaccent
- ring cedilla hungarumlaut ogonek caron Lslash lslash Scaron scaron Zcaron zcaron brokenbar Eth eth
- Yacute yacute Thorn thorn minus multiply onesuperior twosuperior threesuperior onehalf onequarter
- threequarters franc Gbreve gbreve Idotaccent Scedilla scedilla Cacute cacute Ccaron ccaron dcroat);
-
-$VERSION = 0.01; # MJPH 5-AUG-1998 Re-organise data structures
-
-sub init
-{
- my ($k, $v, $c, $i);
- for ($i = 0; $i < $#field_info; $i += 2)
- {
- ($k, $v, $c) = TTF_Init_Fields($field_info[$i], $c, $field_info[$i + 1]);
- next unless defined $k && $k ne "";
- $fields{$k} = $v;
- }
- $i = 0;
- %base_set = map {$_ => $i++} @base_set;
-}
-
-
-=head2 $t->read
-
-Reads the Postscript table into memory from disk
-
-=cut
-
-sub read
-{
- my ($self) = @_;
- my ($dat, $dat1, $i, $off, $c, $maxoff, $form, $angle, $numGlyphs);
- my ($fh) = $self->{' INFILE'};
-
- $numGlyphs = $self->{' PARENT'}{'maxp'}->read->{'numGlyphs'};
- $self->SUPER::read or return $self;
- init unless ($fields{'FormatType'});
- $fh->read($dat, 32);
- TTF_Read_Fields($self, $dat, \%fields);
-
- if (int($self->{'FormatType'} + .5) == 1)
- {
- for ($i = 0; $i < 258; $i++)
- {
- $self->{'VAL'}[$i] = $base_set[$i];
- $self->{'STRINGS'}{$base_set[$i]} = $i unless (defined $self->{'STRINGS'}{$base_set[$i]});
- }
- } elsif (int($self->{'FormatType'} * 2 + .1) == 5)
- {
- $fh->read($dat, 2);
- $numGlyphs = unpack("n", $dat);
- $fh->read($dat, $numGlyphs);
- for ($i = 0; $i < $numGlyphs; $i++)
- {
- $off = unpack("c", substr($dat, $i, 1));
- $self->{'VAL'}[$i] = $base_set[$i + $off];
- $self->{'STRINGS'}{$base_set[$i + $off]} = $i unless (defined $self->{'STRINGS'}{$base_set[$i + $off]});
- }
- } elsif (int($self->{'FormatType'} + .5) == 2)
- {
- my (@strings);
-
- $fh->read($dat, ($numGlyphs + 1) << 1);
- for ($i = 0; $i < $numGlyphs; $i++)
- {
- $off = unpack("n", substr($dat, ($i + 1) << 1, 2));
- $maxoff = $off if (!defined $maxoff || $off > $maxoff);
- }
- for ($i = 0; $i < $maxoff - 257; $i++)
- {
- $fh->read($dat1, 1);
- $off = unpack("C", $dat1);
- $fh->read($dat1, $off);
- $strings[$i] = $dat1;
- }
- for ($i = 0; $i < $numGlyphs; $i++)
- {
- $off = unpack("n", substr($dat, ($i + 1) << 1, 2));
- if ($off > 257)
- {
- $self->{'VAL'}[$i] = $strings[$off - 258];
- $self->{'STRINGS'}{$strings[$off - 258]} = $i;
- }
- else
- {
- $self->{'VAL'}[$i] = $base_set[$off];
- $self->{'STRINGS'}{$base_set[$off]} = $i unless (defined $self->{'STRINGS'}{$base_set[$off]});
- }
- }
- }
- $self;
-}
-
-
-=head2 $t->out($fh)
-
-Writes out a new Postscript name table from memory or copies from disk
-
-=cut
-
-sub out
-{
- my ($self, $fh) = @_;
- my ($i, $num);
-
- return $self->SUPER::out($fh) unless $self->{' read'};
-
- $num = $self->{' PARENT'}{'maxp'}{'numGlyphs'};
-
- init unless ($fields{'FormatType'});
-
- for ($i = $#{$self->{'VAL'}}; !defined $self->{'VAL'}[$i] && $i > 0; $i--)
- { pop(@{$self->{'VAL'}}); }
- if ($#{$self->{'VAL'}} < 0)
- { $self->{'FormatType'} = 3; }
- else
- {
- $self->{'FormatType'} = 1;
- for ($i = 0; $i < $num; $i++)
- {
- if (!defined $base_set{$self->{'VAL'}[$i]})
- {
- $self->{'FormatType'} = 2;
- last;
- }
- elsif ($base_set{$self->{'VAL'}[$i]} != $i)
- { $self->{'FormatType'} = ($no25 ? 2 : 2.5); }
- }
- }
-
- $fh->print(TTF_Out_Fields($self, \%fields, 32));
-
- return $self if (int($self->{'FormatType'} + .4) == 3);
-
- if (int($self->{'FormatType'} + .5) == 2)
- {
- my (@ind, $count);
-
- $fh->print(pack("n", $num));
- for ($i = 0; $i < $num; $i++)
- {
- if (defined $base_set{$self->{'VAL'}[$i]})
- { $fh->print(pack("n", $base_set{$self->{'VAL'}[$i]})); }
- else
- {
- $fh->print(pack("n", $count + 258));
- $ind[$count++] = $i;
- }
- }
- for ($i = 0; $i < $count; $i++)
- {
- $fh->print(pack("C", length($self->{'VAL'}[$ind[$i]])));
- $fh->print($self->{'VAL'}[$ind[$i]]);
- }
- } elsif (int($self->{'FormatType'} * 2 + .5) == 5)
- {
- $fh->print(pack("n", $num));
- for ($i = 0; $i < $num; $i++)
- { $fh->print(pack("c", defined $base_set{$self->{'VAL'}[$i]} ?
- $base_set{$self->{'VAL'}[$i]} - $i : -$i)); }
- }
-
- $self;
-}
-
-
-=head2 $t->XML_element($context, $depth, $key, $val)
-
-Outputs the names as one block of XML
-
-=cut
-
-sub XML_element
-{
- my ($self) = shift;
- my ($context, $depth, $key, $val) = @_;
- my ($fh) = $context->{'fh'};
- my ($i);
-
- return $self->SUPER::XML_element(@_) unless ($key eq 'STRINGS' || $key eq 'VAL');
- return unless ($key eq 'VAL');
-
- $fh->print("$depth<names>\n");
- for ($i = 0; $i <= $#{$self->{'VAL'}}; $i++)
- { $fh->print("$depth$context->{'indent'}<name post='$self->{'VAL'}[$i]' gid='$i'/>\n"); }
- $fh->print("$depth</names>\n");
- $self;
-}
-
-1;
-
-=head1 BUGS
-
-=over 4
-
-=item *
-
-No support for type 4 tables
-
-=back
-
-=head1 AUTHOR
-
-Martin Hosken Martin_Hosken at sil.org. See L<Font::TTF::Font> for copyright and
-licensing.
-
-=cut
-
+package Font::TTF::Post;
+
+=head1 NAME
+
+Font::TTF::Post - Holds the Postscript names for each glyph
+
+=head1 DESCRIPTION
+
+Holds the postscript names for glyphs. Note that they are not held as an
+array, but as indexes into two lists. The first list is the standard Postscript
+name list defined by the TrueType standard. The second comes from the font
+directly.
+
+Looking up a glyph from a Postscript name or a name from a glyph number is
+achieved through methods rather than variable lookup.
+
+This class handles PostScript table types of 1, 2, 2.5 & 3, but not version 4.
+Support for version 2.5 is as per Apple spec rather than MS.
+
+The way to look up Postscript names or glyphs is:
+
+ $pname = $f->{'post'}{'VAL'}[$gnum];
+ $gnum = $f->{'post'}{'STRINGS'}{$pname};
+
+=head1 INSTANCE VARIABLES
+
+Due to different systems having different limitations, there are various class
+variables available to control what post table types can be written.
+
+=over 4
+
+=item $Font::TTF::Post::no25
+
+If set tells Font::TTF::Post::out to use table type 2 instead of 2.5 in case apps
+can't handle version 2.5.
+
+=item VAL
+
+Contains an array indexed by glyph number of Postscript names. This is used when
+writing out a font.
+
+=item STRINGS
+
+An associative array of Postscript names mapping to the highest glyph with that
+name. These may not be in sync with VAL.
+
+=back
+
+In addition there are the standard introductory variables defined in the
+standard:
+
+ FormatType
+ italicAngle
+ underlinePosition
+ underlineThickness
+ isFixedPitch
+ minMemType42
+ maxMemType42
+ minMemType1
+ maxMemType1
+
+=head1 METHODS
+
+=cut
+
+use strict;
+use vars qw(@ISA @base_set %base_set %fields $VERSION $no25 @field_info @base_set);
+require Font::TTF::Table;
+use Font::TTF::Utils;
+
+$no25 = 1; # officially deprecated format 2.5 tables in MS spec 1.3
+
+ at ISA = qw(Font::TTF::Table);
+ at field_info = (
+ 'FormatType' => 'f',
+ 'italicAngle' => 'f',
+ 'underlinePosition' => 's',
+ 'underlineThickness' => 's',
+ 'isFixedPitch' => 'L',
+ 'minMemType42' => 'L',
+ 'maxMemType42' => 'L',
+ 'minMemType1' => 'L',
+ 'maxMemType1' => 'L');
+ at base_set = qw(.notdef .null nonmarkingreturn space exclam quotedbl numbersign dollar percent ampersand quotesingle
+ parenleft parenright asterisk plus comma hyphen period slash zero one two three four five six
+ seven eight nine colon semicolon less equal greater question at A B C D E F G H I J K L M N O P Q
+ R S T U V W X Y Z bracketleft backslash bracketright asciicircum underscore grave a b c d e f g h
+ i j k l m n o p q r s t u v w x y z braceleft bar braceright asciitilde Adieresis Aring Ccedilla
+ Eacute Ntilde Odieresis Udieresis aacute agrave acircumflex adieresis atilde aring ccedilla eacute
+ egrave ecircumflex edieresis iacute igrave icircumflex idieresis ntilde oacute ograve ocircumflex
+ odieresis otilde uacute ugrave ucircumflex udieresis dagger degree cent sterling section bullet
+ paragraph germandbls registered copyright trademark acute dieresis notequal AE Oslash infinity
+ plusminus lessequal greaterequal yen mu partialdiff summation product pi integral ordfeminine
+ ordmasculine Omega ae oslash questiondown exclamdown logicalnot radical florin approxequal
+ Delta guillemotleft guillemotright ellipsis nonbreakingspace Agrave Atilde Otilde OE oe endash emdash
+ quotedblleft quotedblright quoteleft quoteright divide lozenge ydieresis Ydieresis fraction currency
+ guilsinglleft guilsinglright fi fl daggerdbl periodcentered quotesinglbase quotedblbase perthousand
+ Acircumflex Ecircumflex Aacute Edieresis Egrave Iacute Icircumflex Idieresis Igrave Oacute Ocircumflex
+ apple Ograve Uacute Ucircumflex Ugrave dotlessi circumflex tilde macron breve dotaccent
+ ring cedilla hungarumlaut ogonek caron Lslash lslash Scaron scaron Zcaron zcaron brokenbar Eth eth
+ Yacute yacute Thorn thorn minus multiply onesuperior twosuperior threesuperior onehalf onequarter
+ threequarters franc Gbreve gbreve Idotaccent Scedilla scedilla Cacute cacute Ccaron ccaron dcroat);
+
+$VERSION = 0.01; # MJPH 5-AUG-1998 Re-organise data structures
+
+sub init
+{
+ my ($k, $v, $c, $i);
+ for ($i = 0; $i < $#field_info; $i += 2)
+ {
+ ($k, $v, $c) = TTF_Init_Fields($field_info[$i], $c, $field_info[$i + 1]);
+ next unless defined $k && $k ne "";
+ $fields{$k} = $v;
+ }
+ $i = 0;
+ %base_set = map {$_ => $i++} @base_set;
+}
+
+
+=head2 $t->read
+
+Reads the Postscript table into memory from disk
+
+=cut
+
+sub read
+{
+ my ($self) = @_;
+ my ($dat, $dat1, $i, $off, $c, $maxoff, $form, $angle, $numGlyphs);
+ my ($fh) = $self->{' INFILE'};
+
+ $numGlyphs = $self->{' PARENT'}{'maxp'}->read->{'numGlyphs'};
+ $self->SUPER::read or return $self;
+ init unless ($fields{'FormatType'});
+ $fh->read($dat, 32);
+ TTF_Read_Fields($self, $dat, \%fields);
+
+ if (int($self->{'FormatType'} + .5) == 1)
+ {
+ for ($i = 0; $i < 258; $i++)
+ {
+ $self->{'VAL'}[$i] = $base_set[$i];
+ $self->{'STRINGS'}{$base_set[$i]} = $i unless (defined $self->{'STRINGS'}{$base_set[$i]});
+ }
+ } elsif (int($self->{'FormatType'} * 2 + .1) == 5)
+ {
+ $fh->read($dat, 2);
+ $numGlyphs = unpack("n", $dat);
+ $fh->read($dat, $numGlyphs);
+ for ($i = 0; $i < $numGlyphs; $i++)
+ {
+ $off = unpack("c", substr($dat, $i, 1));
+ $self->{'VAL'}[$i] = $base_set[$i + $off];
+ $self->{'STRINGS'}{$base_set[$i + $off]} = $i unless (defined $self->{'STRINGS'}{$base_set[$i + $off]});
+ }
+ } elsif (int($self->{'FormatType'} + .5) == 2)
+ {
+ my (@strings);
+
+ $fh->read($dat, ($numGlyphs + 1) << 1);
+ for ($i = 0; $i < $numGlyphs; $i++)
+ {
+ $off = unpack("n", substr($dat, ($i + 1) << 1, 2));
+ $maxoff = $off if (!defined $maxoff || $off > $maxoff);
+ }
+ for ($i = 0; $i < $maxoff - 257; $i++)
+ {
+ $fh->read($dat1, 1);
+ $off = unpack("C", $dat1);
+ $fh->read($dat1, $off);
+ $strings[$i] = $dat1;
+ }
+ for ($i = 0; $i < $numGlyphs; $i++)
+ {
+ $off = unpack("n", substr($dat, ($i + 1) << 1, 2));
+ if ($off > 257)
+ {
+ $self->{'VAL'}[$i] = $strings[$off - 258];
+ $self->{'STRINGS'}{$strings[$off - 258]} = $i;
+ }
+ else
+ {
+ $self->{'VAL'}[$i] = $base_set[$off];
+ $self->{'STRINGS'}{$base_set[$off]} = $i unless (defined $self->{'STRINGS'}{$base_set[$off]});
+ }
+ }
+ }
+ $self;
+}
+
+
+=head2 $t->out($fh)
+
+Writes out a new Postscript name table from memory or copies from disk
+
+=cut
+
+sub out
+{
+ my ($self, $fh) = @_;
+ my ($i, $num);
+
+ return $self->SUPER::out($fh) unless $self->{' read'};
+
+ $num = $self->{' PARENT'}{'maxp'}{'numGlyphs'};
+
+ init unless ($fields{'FormatType'});
+
+ for ($i = $#{$self->{'VAL'}}; !defined $self->{'VAL'}[$i] && $i > 0; $i--)
+ { pop(@{$self->{'VAL'}}); }
+ if ($#{$self->{'VAL'}} < 0)
+ { $self->{'FormatType'} = 3; }
+ else
+ {
+ $self->{'FormatType'} = 1;
+ for ($i = 0; $i < $num; $i++)
+ {
+ if (!defined $base_set{$self->{'VAL'}[$i]})
+ {
+ $self->{'FormatType'} = 2;
+ last;
+ }
+ elsif ($base_set{$self->{'VAL'}[$i]} != $i)
+ { $self->{'FormatType'} = ($no25 ? 2 : 2.5); }
+ }
+ }
+
+ $fh->print(TTF_Out_Fields($self, \%fields, 32));
+
+ return $self if (int($self->{'FormatType'} + .4) == 3);
+
+ if (int($self->{'FormatType'} + .5) == 2)
+ {
+ my (@ind, $count);
+
+ $fh->print(pack("n", $num));
+ for ($i = 0; $i < $num; $i++)
+ {
+ if (defined $base_set{$self->{'VAL'}[$i]})
+ { $fh->print(pack("n", $base_set{$self->{'VAL'}[$i]})); }
+ else
+ {
+ $fh->print(pack("n", $count + 258));
+ $ind[$count++] = $i;
+ }
+ }
+ for ($i = 0; $i < $count; $i++)
+ {
+ $fh->print(pack("C", length($self->{'VAL'}[$ind[$i]])));
+ $fh->print($self->{'VAL'}[$ind[$i]]);
+ }
+ } elsif (int($self->{'FormatType'} * 2 + .5) == 5)
+ {
+ $fh->print(pack("n", $num));
+ for ($i = 0; $i < $num; $i++)
+ { $fh->print(pack("c", defined $base_set{$self->{'VAL'}[$i]} ?
+ $base_set{$self->{'VAL'}[$i]} - $i : -$i)); }
+ }
+
+ $self;
+}
+
+
+=head2 $t->XML_element($context, $depth, $key, $val)
+
+Outputs the names as one block of XML
+
+=cut
+
+sub XML_element
+{
+ my ($self) = shift;
+ my ($context, $depth, $key, $val) = @_;
+ my ($fh) = $context->{'fh'};
+ my ($i);
+
+ return $self->SUPER::XML_element(@_) unless ($key eq 'STRINGS' || $key eq 'VAL');
+ return unless ($key eq 'VAL');
+
+ $fh->print("$depth<names>\n");
+ for ($i = 0; $i <= $#{$self->{'VAL'}}; $i++)
+ { $fh->print("$depth$context->{'indent'}<name post='$self->{'VAL'}[$i]' gid='$i'/>\n"); }
+ $fh->print("$depth</names>\n");
+ $self;
+}
+
+1;
+
+=head1 BUGS
+
+=over 4
+
+=item *
+
+No support for type 4 tables
+
+=back
+
+=head1 AUTHOR
+
+Martin Hosken Martin_Hosken at sil.org. See L<Font::TTF::Font> for copyright and
+licensing.
+
+=cut
+
Modified: packages/libfont-ttf-perl/trunk/lib/Font/TTF/Prep.pm
===================================================================
--- packages/libfont-ttf-perl/trunk/lib/Font/TTF/Prep.pm 2006-01-17 02:56:43 UTC (rev 1966)
+++ packages/libfont-ttf-perl/trunk/lib/Font/TTF/Prep.pm 2006-01-17 03:07:20 UTC (rev 1967)
@@ -1,89 +1,89 @@
-package Font::TTF::Prep;
-
-=head1 NAME
-
-Font::TTF::Prep - Preparation hinting program. Called when ppem changes
-
-=head1 DESCRIPTION
-
-This is a minimal class adding nothing beyond a table, but is a repository
-for prep type information for those processes brave enough to address hinting.
-
-=cut
-
-use strict;
-use vars qw(@ISA $VERSION);
-use Font::TTF::Utils;
-
- at ISA = qw(Font::TTF::Table);
-
-$VERSION = 0.0001;
-
-
-=head2 $t->read
-
-Reads the data using C<read_dat>.
-
-=cut
-
-sub read
-{
- $_[0]->read_dat;
- $_[0]->{' read'} = 1;
-}
-
-
-=head2 $t->out_xml($context, $depth)
-
-Outputs Prep program as XML
-
-=cut
-
-sub out_xml
-{
- my ($self, $context, $depth) = @_;
- my ($fh) = $context->{'fh'};
- my ($dat);
-
- $self->read;
- $dat = Font::TTF::Utils::XML_binhint($self->{' dat'});
- $dat =~ s/\n(?!$)/\n$depth$context->{'indent'}/omg;
- $fh->print("$depth<code>\n");
- $fh->print("$depth$context->{'indent'}$dat");
- $fh->print("$depth</code>\n");
- $self;
-}
-
-
-=head2 $t->XML_end($context, $tag, %attrs)
-
-Parse all that hinting code
-
-=cut
-
-sub XML_end
-{
- my ($self) = shift;
- my ($context, $tag, %attrs) = @_;
-
- if ($tag eq 'code')
- {
- $self->{' dat'} = Font::TTF::Utils::XML_hintbin($context->{'text'});
- return $context;
- } else
- { return $self->SUPER::XML_end(@_); }
-}
-
-1;
-
-=head1 BUGS
-
-None known
-
-=head1 AUTHOR
-
-Martin Hosken Martin_Hosken at sil.org. See L<Font::TTF::Font> for copyright and
-licensing.
-
-=cut
-
+package Font::TTF::Prep;
+
+=head1 NAME
+
+Font::TTF::Prep - Preparation hinting program. Called when ppem changes
+
+=head1 DESCRIPTION
+
+This is a minimal class adding nothing beyond a table, but is a repository
+for prep type information for those processes brave enough to address hinting.
+
+=cut
+
+use strict;
+use vars qw(@ISA $VERSION);
+use Font::TTF::Utils;
+
+ at ISA = qw(Font::TTF::Table);
+
+$VERSION = 0.0001;
+
+
+=head2 $t->read
+
+Reads the data using C<read_dat>.
+
+=cut
+
+sub read
+{
+ $_[0]->read_dat;
+ $_[0]->{' read'} = 1;
+}
+
+
+=head2 $t->out_xml($context, $depth)
+
+Outputs Prep program as XML
+
+=cut
+
+sub out_xml
+{
+ my ($self, $context, $depth) = @_;
+ my ($fh) = $context->{'fh'};
+ my ($dat);
+
+ $self->read;
+ $dat = Font::TTF::Utils::XML_binhint($self->{' dat'});
+ $dat =~ s/\n(?!$)/\n$depth$context->{'indent'}/omg;
+ $fh->print("$depth<code>\n");
+ $fh->print("$depth$context->{'indent'}$dat");
+ $fh->print("$depth</code>\n");
+ $self;
+}
+
+
+=head2 $t->XML_end($context, $tag, %attrs)
+
+Parse all that hinting code
+
+=cut
+
+sub XML_end
+{
+ my ($self) = shift;
+ my ($context, $tag, %attrs) = @_;
+
+ if ($tag eq 'code')
+ {
+ $self->{' dat'} = Font::TTF::Utils::XML_hintbin($context->{'text'});
+ return $context;
+ } else
+ { return $self->SUPER::XML_end(@_); }
+}
+
+1;
+
+=head1 BUGS
+
+None known
+
+=head1 AUTHOR
+
+Martin Hosken Martin_Hosken at sil.org. See L<Font::TTF::Font> for copyright and
+licensing.
+
+=cut
+
Modified: packages/libfont-ttf-perl/trunk/lib/Font/TTF/Prop.pm
===================================================================
--- packages/libfont-ttf-perl/trunk/lib/Font/TTF/Prop.pm 2006-01-17 02:56:43 UTC (rev 1966)
+++ packages/libfont-ttf-perl/trunk/lib/Font/TTF/Prop.pm 2006-01-17 03:07:20 UTC (rev 1967)
@@ -1,154 +1,154 @@
-package Font::TTF::Prop;
-
-=head1 NAME
-
-Font::TTF::Prop - Glyph Properties table in a font
-
-=head1 DESCRIPTION
-
-=head1 INSTANCE VARIABLES
-
-=item version
-
-=item default
-
-=item lookup
-
-Hash of property values keyed by glyph number
-
-=item lookupFormat
-
-=head1 METHODS
-
-=cut
-
-use strict;
-use vars qw(@ISA);
-use Font::TTF::Utils;
-use Font::TTF::AATutils;
-use Font::TTF::Segarr;
-
- at ISA = qw(Font::TTF::Table);
-
-=head2 $t->read
-
-Reads the table into memory
-
-=cut
-
-sub read
-{
- my ($self) = @_;
- my ($dat, $fh);
- my ($version, $lookupPresent, $default);
-
- $self->SUPER::read or return $self;
-
- $fh = $self->{' INFILE'};
- $fh->read($dat, 8);
- ($version, $lookupPresent, $default) = TTF_Unpack("fSS", $dat);
-
- if ($lookupPresent) {
- my ($format, $lookup) = AAT_read_lookup($fh, 2, $self->{' LENGTH'} - 8, $default);
- $self->{'lookup'} = $lookup;
- $self->{'format'} = $format;
- }
-
- $self->{'version'} = $version;
- $self->{'default'} = $default;
-
- $self;
-}
-
-
-=head2 $t->out($fh)
-
-Writes the table to a file either from memory or by copying
-
-=cut
-
-sub out
-{
- my ($self, $fh) = @_;
- my ($default, $lookup);
-
- return $self->SUPER::out($fh) unless $self->{' read'};
-
- $default = $self->{'default'};
- $lookup = $self->{'lookup'};
- $fh->print(TTF_Pack("fSS", $self->{'version'}, (defined $lookup ? 1 : 0), $default));
-
- AAT_write_lookup($fh, $self->{'format'}, $lookup, 2, $default) if (defined $lookup);
-}
-
-=head2 $t->print($fh)
-
-Prints a human-readable representation of the table
-
-=cut
-
-sub print
-{
- my ($self, $fh) = @_;
- my ($lookup);
-
- $self->read;
-
- $fh = 'STDOUT' unless defined $fh;
-
- $fh->printf("version %f\ndefault %04x # %s\n", $self->{'version'}, $self->{'default'}, meaning_($self->{'default'}));
- $lookup = $self->{'lookup'};
- if (defined $lookup) {
- $fh->printf("format %d\n", $self->{'format'});
- foreach (sort { $a <=> $b } keys %$lookup) {
- $fh->printf("\t%d -> %04x # %s\n", $_, $lookup->{$_}, meaning_($lookup->{$_}));
- }
- }
-}
-
-sub meaning_
-{
- my ($val) = @_;
- my ($res);
-
- my @types = (
- "Strong left-to-right",
- "Strong right-to-left",
- "Arabic letter",
- "European number",
- "European number separator",
- "European number terminator",
- "Arabic number",
- "Common number separator",
- "Block separator",
- "Segment separator",
- "Whitespace",
- "Other neutral");
- $res = $types[$val & 0x001f] or ("Undefined [" . ($val & 0x001f) . "]");
-
- $res .= ", floater" if $val & 0x8000;
- $res .= ", hang left" if $val & 0x4000;
- $res .= ", hang right" if $val & 0x2000;
- $res .= ", attaches on right" if $val & 0x0080;
- $res .= ", pair" if $val & 0x1000;
- my $pairOffset = ($val & 0x0f00) >> 8;
- $pairOffset = $pairOffset - 16 if $pairOffset > 7;
- $res .= $pairOffset > 0 ? " +" . $pairOffset : $pairOffset < 0 ? " " . $pairOffset : "";
-
- $res;
-}
-
-1;
-
-
-=head1 BUGS
-
-None known
-
-=head1 AUTHOR
-
-Jonathan Kew L<Jonathan_Kew at sil.org>. See L<Font::TTF::Font> for copyright and
-licensing.
-
-=cut
-
+package Font::TTF::Prop;
+
+=head1 NAME
+
+Font::TTF::Prop - Glyph Properties table in a font
+
+=head1 DESCRIPTION
+
+=head1 INSTANCE VARIABLES
+
+=item version
+
+=item default
+
+=item lookup
+
+Hash of property values keyed by glyph number
+
+=item lookupFormat
+
+=head1 METHODS
+
+=cut
+
+use strict;
+use vars qw(@ISA);
+use Font::TTF::Utils;
+use Font::TTF::AATutils;
+use Font::TTF::Segarr;
+
+ at ISA = qw(Font::TTF::Table);
+
+=head2 $t->read
+
+Reads the table into memory
+
+=cut
+
+sub read
+{
+ my ($self) = @_;
+ my ($dat, $fh);
+ my ($version, $lookupPresent, $default);
+
+ $self->SUPER::read or return $self;
+
+ $fh = $self->{' INFILE'};
+ $fh->read($dat, 8);
+ ($version, $lookupPresent, $default) = TTF_Unpack("fSS", $dat);
+
+ if ($lookupPresent) {
+ my ($format, $lookup) = AAT_read_lookup($fh, 2, $self->{' LENGTH'} - 8, $default);
+ $self->{'lookup'} = $lookup;
+ $self->{'format'} = $format;
+ }
+
+ $self->{'version'} = $version;
+ $self->{'default'} = $default;
+
+ $self;
+}
+
+
+=head2 $t->out($fh)
+
+Writes the table to a file either from memory or by copying
+
+=cut
+
+sub out
+{
+ my ($self, $fh) = @_;
+ my ($default, $lookup);
+
+ return $self->SUPER::out($fh) unless $self->{' read'};
+
+ $default = $self->{'default'};
+ $lookup = $self->{'lookup'};
+ $fh->print(TTF_Pack("fSS", $self->{'version'}, (defined $lookup ? 1 : 0), $default));
+
+ AAT_write_lookup($fh, $self->{'format'}, $lookup, 2, $default) if (defined $lookup);
+}
+
+=head2 $t->print($fh)
+
+Prints a human-readable representation of the table
+
+=cut
+
+sub print
+{
+ my ($self, $fh) = @_;
+ my ($lookup);
+
+ $self->read;
+
+ $fh = 'STDOUT' unless defined $fh;
+
+ $fh->printf("version %f\ndefault %04x # %s\n", $self->{'version'}, $self->{'default'}, meaning_($self->{'default'}));
+ $lookup = $self->{'lookup'};
+ if (defined $lookup) {
+ $fh->printf("format %d\n", $self->{'format'});
+ foreach (sort { $a <=> $b } keys %$lookup) {
+ $fh->printf("\t%d -> %04x # %s\n", $_, $lookup->{$_}, meaning_($lookup->{$_}));
+ }
+ }
+}
+
+sub meaning_
+{
+ my ($val) = @_;
+ my ($res);
+
+ my @types = (
+ "Strong left-to-right",
+ "Strong right-to-left",
+ "Arabic letter",
+ "European number",
+ "European number separator",
+ "European number terminator",
+ "Arabic number",
+ "Common number separator",
+ "Block separator",
+ "Segment separator",
+ "Whitespace",
+ "Other neutral");
+ $res = $types[$val & 0x001f] or ("Undefined [" . ($val & 0x001f) . "]");
+
+ $res .= ", floater" if $val & 0x8000;
+ $res .= ", hang left" if $val & 0x4000;
+ $res .= ", hang right" if $val & 0x2000;
+ $res .= ", attaches on right" if $val & 0x0080;
+ $res .= ", pair" if $val & 0x1000;
+ my $pairOffset = ($val & 0x0f00) >> 8;
+ $pairOffset = $pairOffset - 16 if $pairOffset > 7;
+ $res .= $pairOffset > 0 ? " +" . $pairOffset : $pairOffset < 0 ? " " . $pairOffset : "";
+
+ $res;
+}
+
+1;
+
+
+=head1 BUGS
+
+None known
+
+=head1 AUTHOR
+
+Jonathan Kew L<Jonathan_Kew at sil.org>. See L<Font::TTF::Font> for copyright and
+licensing.
+
+=cut
+
Modified: packages/libfont-ttf-perl/trunk/lib/Font/TTF/Segarr.pm
===================================================================
--- packages/libfont-ttf-perl/trunk/lib/Font/TTF/Segarr.pm 2006-01-17 02:56:43 UTC (rev 1966)
+++ packages/libfont-ttf-perl/trunk/lib/Font/TTF/Segarr.pm 2006-01-17 03:07:20 UTC (rev 1967)
@@ -1,376 +1,376 @@
-package Font::TTF::Segarr;
-
-=head1 NAME
-
-Font::TTF::Segarr - Segmented array
-
-=head1 DESCRIPTION
-
-Holds data either directly or indirectly as a series of arrays. This class
-looks after the set of arrays and masks the individual sub-arrays, thus saving
-a class, we hope.
-
-=head1 INSTANCE VARIABLES
-
-All instance variables do not start with a space.
-
-The segmented array is simply an array of segments
-
-Each segment is a more complex affair:
-
-=over 4
-
-=item START
-
-In terms of the array, the address for the 0th element in this segment.
-
-=item LEN
-
-Number of elements in this segment
-
-=item VAL
-
-The array which contains the elements
-
-=back
-
-=head1 METHODS
-
-=cut
-
-use strict;
-use vars qw(@types $VERSION);
-$VERSION = 0.0001;
-
- at types = ('', 'C', 'n', '', 'N');
-
-=head2 Font::TTF::Segarr->new($size)
-
-Creates a new segmented array with a given data size
-
-=cut
-
-sub new
-{
- my ($class) = @_;
- my ($self) = [];
-
- bless $self, (ref($class) || $class);
-}
-
-
-=head2 $s->fastadd_segment($start, $is_sparse, @dat)
-
-Creates a new segment and adds it to the array assuming no overlap between
-the new segment and any others in the array. $is_sparse indicates whether the
-passed in array contains C<undef>s or not. If false no checking is done (which
-is faster, but riskier). If equal to 2 then 0 is considered undef as well.
-
-Returns the number of segments inserted.
-
-=cut
-
-sub fastadd_segment
-{
- my ($self) = shift;
- my ($start) = shift;
- my ($sparse) = shift;
- my ($p, $i, $seg, @seg);
-
-
- if ($sparse)
- {
- for ($i = 0; $i <= $#_; $i++)
- {
- if (!defined $seg && (($sparse != 2 && defined $_[$i]) || $_[$i] != 0))
- { $seg->{'START'} = $start + $i; $seg->{'VAL'} = []; }
-
- if (defined $seg && (($sparse == 2 && $_[$i] == 0) || !defined $_[$i]))
- {
- $seg->{'LEN'} = $start + $i - $seg->{'START'};
- push(@seg, $seg);
- $seg = undef;
- } elsif (defined $seg)
- { push (@{$seg->{'VAL'}}, $_[$i]); }
- }
- if (defined $seg)
- {
- push(@seg, $seg);
- $seg->{'LEN'} = $start + $i - $seg->{'START'};
- }
- } else
- {
- $seg->{'START'} = $start;
- $seg->{'LEN'} = $#_ + 1;
- $seg->{'VAL'} = [@_];
- @seg = ($seg);
- }
-
- for ($i = 0; $i <= $#$self; $i++)
- {
- if ($self->[$i]{'START'} > $start)
- {
- splice(@$self, $i, 0, @seg);
- return wantarray ? @seg : scalar(@seg);
- }
- }
- push(@$self, @seg);
- return wantarray ? @seg : scalar(@seg);
-}
-
-
-=head2 $s->add_segment($start, $overwrite, @dat)
-
-Creates a new segment and adds it to the array allowing for possible overlaps
-between the new segment and the existing ones. In the case of overlaps, elements
-from the new segment are deleted unless $overwrite is set in which case the
-elements already there are over-written.
-
-This method also checks the data coming in to see if it is sparse (i.e. contains
-undef values). Gaps cause new segments to be created or not to over-write existing
-values.
-
-=cut
-
-sub add_segment
-{
- my ($self) = shift;
- my ($start) = shift;
- my ($over) = shift;
- my ($seg, $i, $s, $offset, $j, $newi);
-
- return $self->fastadd_segment($start, $over, @_) if ($#$self < 0);
- $offset = 0;
- for ($i = 0; $i <= $#$self && $offset <= $#_; $i++)
- {
- $s = $self->[$i];
- if ($s->{'START'} <= $start + $offset) # only < for $offset == 0
- {
- if ($s->{'START'} + $s->{'LEN'} > $start + $#_)
- {
- for ($j = $offset; $j <= $#_; $j++)
- {
- if ($over)
- { $s->{'VAL'}[$start - $s->{'START'} + $j] = $_[$j] if defined $_[$j]; }
- else
- { $s->{'VAL'}[$start - $s->{'START'} + $j] ||= $_[$j] if defined $_[$j]; }
- }
- $offset = $#_ + 1;
- last;
- } elsif ($s->{'START'} + $s->{'LEN'} > $start + $offset) # is $offset needed here?
- {
- for ($j = $offset; $j < $s->{'START'} + $s->{'LEN'} - $start; $j++)
- {
- if ($over)
- { $s->{'VAL'}[$start - $s->{'START'} + $j] = $_[$j] if defined $_[$j]; }
- else
- { $s->{'VAL'}[$start - $s->{'START'} + $j] ||= $_[$j] if defined $_[$j]; }
- }
- $offset = $s->{'START'} + $s->{'LEN'} - $start;
- }
- } else # new seg please
- {
- if ($s->{'START'} > $start + $#_ + 1)
- {
- $i += $self->fastadd_segment($start + $offset, 1, @_[$offset .. $#_]) - 1;
- $offset = $#_ + 1;
- }
- else
- {
- $i += $self->fastadd_segment($start + $offset, 1, @_[$offset .. $s->{'START'} - $start]) - 1;
- $offset = $s->{'START'} - $start + 1;
- }
- }
- }
- if ($offset <= $#_)
- {
- $seg->{'START'} = $start + $offset;
- $seg->{'LEN'} = $#_ - $offset + 1;
- $seg->{'VAL'} = [@_[$offset .. $#_]];
- push (@$self, $seg);
- }
- $self->tidy;
-}
-
-
-=head2 $s->tidy
-
-Merges any immediately adjacent segments
-
-=cut
-
-sub tidy
-{
- my ($self) = @_;
- my ($i, $sl, $s);
-
- for ($i = 1; $i <= $#$self; $i++)
- {
- $sl = $self->[$i - 1];
- $s = $self->[$i];
- if ($s->{'START'} == $sl->{'START'} + $sl->{'LEN'})
- {
- $sl->{'LEN'} += $s->{'LEN'};
- push (@{$sl->{'VAL'}}, @{$s->{'VAL'}});
- splice(@$self, $i, 1);
- $i--;
- }
- }
- $self;
-}
-
-
-=head2 $s->at($addr, [$len])
-
-Looks up the data held at the given address by locating the appropriate segment
-etc. If $len > 1 then returns an array of values, spaces being filled with undef.
-
-=cut
-
-sub at
-{
- my ($self, $addr, $len) = @_;
- my ($i, $dat, $s, @res, $offset);
-
- $len = 1 unless defined $len;
- $offset = 0;
- for ($i = 0; $i <= $#$self; $i++)
- {
- $s = $self->[$i];
- next if ($s->{'START'} + $s->{'LEN'} < $addr + $offset); # only fires on $offset == 0
- if ($s->{'START'} > $addr + $offset)
- {
- push (@res, (undef) x ($s->{'START'} > $addr + $len ?
- $len - $offset : $s->{'START'} - $addr - $offset));
- $offset = $s->{'START'} - $addr;
- }
- last if ($s->{'START'} >= $addr + $len);
-
- if ($s->{'START'} + $s->{'LEN'} >= $addr + $len)
- {
- push (@res, @{$s->{'VAL'}}[$addr + $offset - $s->{'START'} ..
- $addr + $len - $s->{'START'} - 1]);
- $offset = $len;
- last;
- } else
- {
- push (@res, @{$s->{'VAL'}}[$addr + $offset - $s->{'START'} .. $s->{'LEN'} - 1]);
- $offset = $s->{'START'} + $s->{'LEN'} - $addr;
- }
- }
- push (@res, (undef) x ($len - $offset)) if ($offset < $len);
- return wantarray ? @res : $res[0];
-}
-
-
-=head2 $s->remove($addr, [$len])
-
-Removes the item or items from addr returning them as an array or the first
-value in a scalar context. This is very like C<at>, including padding with
-undef, but it deletes stuff as it goes.
-
-=cut
-
-sub remove
-{
- my ($self, $addr, $len) = @_;
- my ($i, $dat, $s, @res, $offset);
-
- $len = 1 unless defined $len;
- $offset = 0;
- for ($i = 0; $i <= $#$self; $i++)
- {
- $s = $self->[$i];
- next if ($s->{'START'} + $s->{'LEN'} < $addr + $offset);
- if ($s->{'START'} > $addr + $offset)
- {
- push (@res, (undef) x ($s->{'START'} > $addr + $len ?
- $len - $offset : $s->{'START'} - $addr - $offset));
- $offset = $s->{'START'} - $addr;
- }
- last if ($s->{'START'} >= $addr + $len);
-
- unless ($s->{'START'} == $addr + $offset)
- {
- my ($seg) = {};
-
- $seg->{'START'} = $s->{'START'};
- $seg->{'LEN'} = $addr + $offset - $s->{'START'};
- $seg->{'VAL'} = [splice(@{$s->{'VAL'}}, 0, $addr + $offset - $s->{'START'})];
- $s->{'LEN'} -= $addr + $offset - $s->{'START'};
- $s->{'START'} = $addr + $offset;
-
- splice(@$self, $i, 0, $seg);
- $i++;
- }
-
- if ($s->{'START'} + $s->{'LEN'} >= $addr + $len)
- {
- push (@res, splice(@{$s->{'VAL'}}, 0, $len - $offset));
- $s->{'LEN'} -= $len - $offset;
- $s->{'START'} += $len - $offset;
- $offset = $len;
- last;
- } else
- {
- push (@res, @{$s->{'VAL'}});
- $offset = $s->{'START'} + $s->{'LEN'} - $addr;
- splice(@$self, $i, 0);
- $i--;
- }
- }
- push (@res, (undef) x ($len - $offset)) if ($offset < $len);
- return wantarray ? @res : $res[0];
-}
-
-
-=head2 $s->copy
-
-Deep copies this array
-
-=cut
-
-sub copy
-{
- my ($self) = @_;
- my ($res, $p);
-
- $res = [];
- foreach $p (@$self)
- { push (@$res, $self->copy_seg($p)); }
- $res;
-}
-
-
-=head2 $s->copy_seg($seg)
-
-Creates a deep copy of a segment
-
-=cut
-
-sub copy_seg
-{
- my ($self, $seg) = @_;
- my ($p, $res);
-
- $res = {};
- $res->{'VAL'} = [@{$seg->{'VAL'}}];
- foreach $p (keys %$seg)
- { $res->{$p} = $seg->{$p} unless defined $res->{$p}; }
- $res;
-}
-
-
-1;
-
-=head1 BUGS
-
-No known bugs.
-
-=head1 AUTHOR
-
-Martin Hosken Martin_Hosken at sil.org. See L<Font::TTF::Font> for copyright and
-licensing.
-
-=cut
-
+package Font::TTF::Segarr;
+
+=head1 NAME
+
+Font::TTF::Segarr - Segmented array
+
+=head1 DESCRIPTION
+
+Holds data either directly or indirectly as a series of arrays. This class
+looks after the set of arrays and masks the individual sub-arrays, thus saving
+a class, we hope.
+
+=head1 INSTANCE VARIABLES
+
+All instance variables do not start with a space.
+
+The segmented array is simply an array of segments
+
+Each segment is a more complex affair:
+
+=over 4
+
+=item START
+
+In terms of the array, the address for the 0th element in this segment.
+
+=item LEN
+
+Number of elements in this segment
+
+=item VAL
+
+The array which contains the elements
+
+=back
+
+=head1 METHODS
+
+=cut
+
+use strict;
+use vars qw(@types $VERSION);
+$VERSION = 0.0001;
+
+ at types = ('', 'C', 'n', '', 'N');
+
+=head2 Font::TTF::Segarr->new($size)
+
+Creates a new segmented array with a given data size
+
+=cut
+
+sub new
+{
+ my ($class) = @_;
+ my ($self) = [];
+
+ bless $self, (ref($class) || $class);
+}
+
+
+=head2 $s->fastadd_segment($start, $is_sparse, @dat)
+
+Creates a new segment and adds it to the array assuming no overlap between
+the new segment and any others in the array. $is_sparse indicates whether the
+passed in array contains C<undef>s or not. If false no checking is done (which
+is faster, but riskier). If equal to 2 then 0 is considered undef as well.
+
+Returns the number of segments inserted.
+
+=cut
+
+sub fastadd_segment
+{
+ my ($self) = shift;
+ my ($start) = shift;
+ my ($sparse) = shift;
+ my ($p, $i, $seg, @seg);
+
+
+ if ($sparse)
+ {
+ for ($i = 0; $i <= $#_; $i++)
+ {
+ if (!defined $seg && (($sparse != 2 && defined $_[$i]) || $_[$i] != 0))
+ { $seg->{'START'} = $start + $i; $seg->{'VAL'} = []; }
+
+ if (defined $seg && (($sparse == 2 && $_[$i] == 0) || !defined $_[$i]))
+ {
+ $seg->{'LEN'} = $start + $i - $seg->{'START'};
+ push(@seg, $seg);
+ $seg = undef;
+ } elsif (defined $seg)
+ { push (@{$seg->{'VAL'}}, $_[$i]); }
+ }
+ if (defined $seg)
+ {
+ push(@seg, $seg);
+ $seg->{'LEN'} = $start + $i - $seg->{'START'};
+ }
+ } else
+ {
+ $seg->{'START'} = $start;
+ $seg->{'LEN'} = $#_ + 1;
+ $seg->{'VAL'} = [@_];
+ @seg = ($seg);
+ }
+
+ for ($i = 0; $i <= $#$self; $i++)
+ {
+ if ($self->[$i]{'START'} > $start)
+ {
+ splice(@$self, $i, 0, @seg);
+ return wantarray ? @seg : scalar(@seg);
+ }
+ }
+ push(@$self, @seg);
+ return wantarray ? @seg : scalar(@seg);
+}
+
+
+=head2 $s->add_segment($start, $overwrite, @dat)
+
+Creates a new segment and adds it to the array allowing for possible overlaps
+between the new segment and the existing ones. In the case of overlaps, elements
+from the new segment are deleted unless $overwrite is set in which case the
+elements already there are over-written.
+
+This method also checks the data coming in to see if it is sparse (i.e. contains
+undef values). Gaps cause new segments to be created or not to over-write existing
+values.
+
+=cut
+
+sub add_segment
+{
+ my ($self) = shift;
+ my ($start) = shift;
+ my ($over) = shift;
+ my ($seg, $i, $s, $offset, $j, $newi);
+
+ return $self->fastadd_segment($start, $over, @_) if ($#$self < 0);
+ $offset = 0;
+ for ($i = 0; $i <= $#$self && $offset <= $#_; $i++)
+ {
+ $s = $self->[$i];
+ if ($s->{'START'} <= $start + $offset) # only < for $offset == 0
+ {
+ if ($s->{'START'} + $s->{'LEN'} > $start + $#_)
+ {
+ for ($j = $offset; $j <= $#_; $j++)
+ {
+ if ($over)
+ { $s->{'VAL'}[$start - $s->{'START'} + $j] = $_[$j] if defined $_[$j]; }
+ else
+ { $s->{'VAL'}[$start - $s->{'START'} + $j] ||= $_[$j] if defined $_[$j]; }
+ }
+ $offset = $#_ + 1;
+ last;
+ } elsif ($s->{'START'} + $s->{'LEN'} > $start + $offset) # is $offset needed here?
+ {
+ for ($j = $offset; $j < $s->{'START'} + $s->{'LEN'} - $start; $j++)
+ {
+ if ($over)
+ { $s->{'VAL'}[$start - $s->{'START'} + $j] = $_[$j] if defined $_[$j]; }
+ else
+ { $s->{'VAL'}[$start - $s->{'START'} + $j] ||= $_[$j] if defined $_[$j]; }
+ }
+ $offset = $s->{'START'} + $s->{'LEN'} - $start;
+ }
+ } else # new seg please
+ {
+ if ($s->{'START'} > $start + $#_ + 1)
+ {
+ $i += $self->fastadd_segment($start + $offset, 1, @_[$offset .. $#_]) - 1;
+ $offset = $#_ + 1;
+ }
+ else
+ {
+ $i += $self->fastadd_segment($start + $offset, 1, @_[$offset .. $s->{'START'} - $start]) - 1;
+ $offset = $s->{'START'} - $start + 1;
+ }
+ }
+ }
+ if ($offset <= $#_)
+ {
+ $seg->{'START'} = $start + $offset;
+ $seg->{'LEN'} = $#_ - $offset + 1;
+ $seg->{'VAL'} = [@_[$offset .. $#_]];
+ push (@$self, $seg);
+ }
+ $self->tidy;
+}
+
+
+=head2 $s->tidy
+
+Merges any immediately adjacent segments
+
+=cut
+
+sub tidy
+{
+ my ($self) = @_;
+ my ($i, $sl, $s);
+
+ for ($i = 1; $i <= $#$self; $i++)
+ {
+ $sl = $self->[$i - 1];
+ $s = $self->[$i];
+ if ($s->{'START'} == $sl->{'START'} + $sl->{'LEN'})
+ {
+ $sl->{'LEN'} += $s->{'LEN'};
+ push (@{$sl->{'VAL'}}, @{$s->{'VAL'}});
+ splice(@$self, $i, 1);
+ $i--;
+ }
+ }
+ $self;
+}
+
+
+=head2 $s->at($addr, [$len])
+
+Looks up the data held at the given address by locating the appropriate segment
+etc. If $len > 1 then returns an array of values, spaces being filled with undef.
+
+=cut
+
+sub at
+{
+ my ($self, $addr, $len) = @_;
+ my ($i, $dat, $s, @res, $offset);
+
+ $len = 1 unless defined $len;
+ $offset = 0;
+ for ($i = 0; $i <= $#$self; $i++)
+ {
+ $s = $self->[$i];
+ next if ($s->{'START'} + $s->{'LEN'} < $addr + $offset); # only fires on $offset == 0
+ if ($s->{'START'} > $addr + $offset)
+ {
+ push (@res, (undef) x ($s->{'START'} > $addr + $len ?
+ $len - $offset : $s->{'START'} - $addr - $offset));
+ $offset = $s->{'START'} - $addr;
+ }
+ last if ($s->{'START'} >= $addr + $len);
+
+ if ($s->{'START'} + $s->{'LEN'} >= $addr + $len)
+ {
+ push (@res, @{$s->{'VAL'}}[$addr + $offset - $s->{'START'} ..
+ $addr + $len - $s->{'START'} - 1]);
+ $offset = $len;
+ last;
+ } else
+ {
+ push (@res, @{$s->{'VAL'}}[$addr + $offset - $s->{'START'} .. $s->{'LEN'} - 1]);
+ $offset = $s->{'START'} + $s->{'LEN'} - $addr;
+ }
+ }
+ push (@res, (undef) x ($len - $offset)) if ($offset < $len);
+ return wantarray ? @res : $res[0];
+}
+
+
+=head2 $s->remove($addr, [$len])
+
+Removes the item or items from addr returning them as an array or the first
+value in a scalar context. This is very like C<at>, including padding with
+undef, but it deletes stuff as it goes.
+
+=cut
+
+sub remove
+{
+ my ($self, $addr, $len) = @_;
+ my ($i, $dat, $s, @res, $offset);
+
+ $len = 1 unless defined $len;
+ $offset = 0;
+ for ($i = 0; $i <= $#$self; $i++)
+ {
+ $s = $self->[$i];
+ next if ($s->{'START'} + $s->{'LEN'} < $addr + $offset);
+ if ($s->{'START'} > $addr + $offset)
+ {
+ push (@res, (undef) x ($s->{'START'} > $addr + $len ?
+ $len - $offset : $s->{'START'} - $addr - $offset));
+ $offset = $s->{'START'} - $addr;
+ }
+ last if ($s->{'START'} >= $addr + $len);
+
+ unless ($s->{'START'} == $addr + $offset)
+ {
+ my ($seg) = {};
+
+ $seg->{'START'} = $s->{'START'};
+ $seg->{'LEN'} = $addr + $offset - $s->{'START'};
+ $seg->{'VAL'} = [splice(@{$s->{'VAL'}}, 0, $addr + $offset - $s->{'START'})];
+ $s->{'LEN'} -= $addr + $offset - $s->{'START'};
+ $s->{'START'} = $addr + $offset;
+
+ splice(@$self, $i, 0, $seg);
+ $i++;
+ }
+
+ if ($s->{'START'} + $s->{'LEN'} >= $addr + $len)
+ {
+ push (@res, splice(@{$s->{'VAL'}}, 0, $len - $offset));
+ $s->{'LEN'} -= $len - $offset;
+ $s->{'START'} += $len - $offset;
+ $offset = $len;
+ last;
+ } else
+ {
+ push (@res, @{$s->{'VAL'}});
+ $offset = $s->{'START'} + $s->{'LEN'} - $addr;
+ splice(@$self, $i, 0);
+ $i--;
+ }
+ }
+ push (@res, (undef) x ($len - $offset)) if ($offset < $len);
+ return wantarray ? @res : $res[0];
+}
+
+
+=head2 $s->copy
+
+Deep copies this array
+
+=cut
+
+sub copy
+{
+ my ($self) = @_;
+ my ($res, $p);
+
+ $res = [];
+ foreach $p (@$self)
+ { push (@$res, $self->copy_seg($p)); }
+ $res;
+}
+
+
+=head2 $s->copy_seg($seg)
+
+Creates a deep copy of a segment
+
+=cut
+
+sub copy_seg
+{
+ my ($self, $seg) = @_;
+ my ($p, $res);
+
+ $res = {};
+ $res->{'VAL'} = [@{$seg->{'VAL'}}];
+ foreach $p (keys %$seg)
+ { $res->{$p} = $seg->{$p} unless defined $res->{$p}; }
+ $res;
+}
+
+
+1;
+
+=head1 BUGS
+
+No known bugs.
+
+=head1 AUTHOR
+
+Martin Hosken Martin_Hosken at sil.org. See L<Font::TTF::Font> for copyright and
+licensing.
+
+=cut
+
Modified: packages/libfont-ttf-perl/trunk/lib/Font/TTF/Table.pm
===================================================================
--- packages/libfont-ttf-perl/trunk/lib/Font/TTF/Table.pm 2006-01-17 02:56:43 UTC (rev 1966)
+++ packages/libfont-ttf-perl/trunk/lib/Font/TTF/Table.pm 2006-01-17 03:07:20 UTC (rev 1967)
@@ -1,382 +1,382 @@
-package Font::TTF::Table;
-
-=head1 NAME
-
-Font::TTF::Table - Superclass for tables and used for tables we don't have a class for
-
-=head1 DESCRIPTION
-
-Looks after the purely table aspects of a TTF table, such as whether the table
-has been read before, locating the file pointer, etc. Also copies tables from
-input to output.
-
-=head1 INSTANCE VARIABLES
-
-Instance variables start with a space
-
-=over 4
-
-=item read
-
-Flag which indicates that the table has already been read from file.
-
-=item dat
-
-Allows the creation of unspecific tables. Data is simply output to any font
-file being created.
-
-=item INFILE
-
-The read file handle
-
-=item OFFSET
-
-Location of the file in the input file
-
-=item LENGTH
-
-Length in the input directory
-
-=item CSUM
-
-Checksum read from the input file's directory
-
-=item PARENT
-
-The L<Font::TTF::Font> that table is part of
-
-=back
-
-=head1 METHODS
-
-=cut
-
-use strict;
-use vars qw($VERSION);
-use Font::TTF::Utils;
-
-$VERSION = 0.0001;
-
-=head2 Font::TTF::Table->new(%parms)
-
-Creates a new table or subclass. Table instance variables are passed in
-at this point as an associative array.
-
-=cut
-
-sub new
-{
- my ($class, %parms) = @_;
- my ($self) = {};
- my ($p);
-
- $class = ref($class) || $class;
- foreach $p (keys %parms)
- { $self->{" $p"} = $parms{$p}; }
- bless $self, $class;
-}
-
-
-=head2 $t->read
-
-Reads the table from the input file. Acts as a superclass to all true tables.
-This method marks the table as read and then just sets the input file pointer
-but does not read any data. If the table has already been read, then returns
-C<undef> else returns C<$self>
-
-=cut
-
-sub read
-{
- my ($self) = @_;
-
- return $self->read_dat if (ref($self) eq "Font::TTF::Table");
- return undef if $self->{' read'};
- $self->{' INFILE'}->seek($self->{' OFFSET'}, 0);
- $self->{' read'} = 1;
- $self;
-}
-
-
-=head2 $t->read_dat
-
-Reads the table into the C<dat> instance variable for those tables which don't
-know any better
-
-=cut
-
-sub read_dat
-{
- my ($self) = @_;
-
-# can't just $self->read here otherwise those tables which start their read sub with
-# $self->read_dat are going to permanently loop
- return undef if ($self->{' read'});
-# $self->{' read'} = 1; # Let read do this, now out will call us for subclasses
- $self->{' INFILE'}->seek($self->{' OFFSET'}, 0);
- $self->{' INFILE'}->read($self->{' dat'}, $self->{' LENGTH'});
- $self;
-}
-
-=head2 $t->out($fh)
-
-Writes out the table to the font file. If there is anything in the
-C<data> instance variable then this is output, otherwise the data is copied
-from the input file to the output
-
-=cut
-
-sub out
-{
- my ($self, $fh) = @_;
- my ($dat, $i, $len, $count);
-
- if (defined $self->{' dat'})
- {
- $fh->print($self->{' dat'});
- return $self;
- }
-
- return undef unless defined $self->{' INFILE'};
- $self->{' INFILE'}->seek($self->{' OFFSET'}, 0);
- $len = $self->{' LENGTH'};
- while ($len > 0)
- {
- $count = ($len > 4096) ? 4096 : $len;
- $self->{' INFILE'}->read($dat, $count);
- $fh->print($dat);
- $len -= $count;
- }
- $self;
-}
-
-
-=head2 $t->out_xml($context)
-
-Outputs this table in XML format. The table is first read (if not already read) and then if
-there is no subclass, then the data is dumped as hex data
-
-=cut
-
-sub out_xml
-{
- my ($self, $context, $depth) = @_;
- my ($k);
-
- if (ref($self) eq __PACKAGE__)
- {
- $self->read_dat;
- Font::TTF::Utils::XML_hexdump($context, $depth, $self->{' dat'});
- }
- else
- {
- $self->read;
- foreach $k (sort grep {$_ !~ m/^\s/o} keys %{$self})
- {
- $self->XML_element($context, $depth, $k, $self->{$k});
- }
- }
- $self;
-}
-
-
-=head2 $t->XML_element
-
-Output a particular element based on its contents.
-
-=cut
-
-sub XML_element
-{
- my ($self, $context, $depth, $k, $dat) = @_;
- my ($fh) = $context->{'fh'};
- my ($ndepth, $d);
-
- return unless defined $dat;
-
- if (!ref($dat))
- {
- $fh->printf("%s<%s>%s</%s>\n", $depth, $k, $dat, $k);
- return $self;
- }
-
- $fh->printf("%s<%s>\n", $depth, $k);
- $ndepth = $depth . $context->{'indent'};
-
- if (ref($dat) eq 'SCALAR')
- { $self->XML_element($context, $ndepth, 'scalar', $$dat); }
- elsif (ref($dat) eq 'ARRAY')
- {
- foreach $d (@{$dat})
- { $self->XML_element($context, $ndepth, 'elem', $d); }
- }
- elsif (ref($dat) eq 'HASH')
- {
- foreach $d (sort grep {$_ !~ m/^\s/o} keys %{$dat})
- { $self->XML_element($context, $ndepth, $d, $dat->{$d}); }
- }
- else
- {
- $context->{'name'} = ref($dat);
- $context->{'name'} =~ s/^.*://o;
- $dat->out_xml($context, $ndepth);
- }
-
- $fh->printf("%s</%s>\n", $depth, $k);
- $self;
-}
-
-
-=head2 $t->XML_end($context, $tag, %attrs)
-
-Handles the default type of <data> for those tables which aren't subclassed
-
-=cut
-
-sub XML_end
-{
- my ($self, $context, $tag, %attrs) = @_;
- my ($dat, $addr);
-
- return undef unless ($tag eq 'data');
- $dat = $context->{'text'};
- $dat =~ s/([0-9a-f]{2})\s*/hex($1)/oig;
- if (defined $attrs{'addr'})
- { $addr = hex($attrs{'addr'}); }
- else
- { $addr = length($self->{' dat'}); }
- substr($self->{' dat'}, $addr, length($dat)) = $dat;
- return $context;
-}
-
-
-=head2 $t->dirty($val)
-
-This sets the dirty flag to the given value or 1 if no given value. It returns the
-value of the flag
-
-=cut
-
-sub dirty
-{
- my ($self, $val) = @_;
- my ($res) = $self->{' isDirty'};
-
- $self->{' isDirty'} = defined $val ? $val : 1;
- $res;
-}
-
-=head2 $t->update
-
-Each table knows how to update itself. This consists of doing whatever work
-is required to ensure that the memory version of the table is consistent
-and that other parameters in other tables have been updated accordingly.
-I.e. by the end of sending C<update> to all the tables, the memory version
-of the font should be entirely consistent.
-
-Some tables which do no work indicate to themselves the need to update
-themselves by setting isDirty above 1. This method resets that accordingly.
-
-=cut
-
-sub update
-{
- my ($self) = @_;
-
- if ($self->{' isDirty'})
- {
- $self->read;
- $self->{' isDirty'} = 0;
- return $self;
- }
- else
- { return undef; }
-}
-
-
-=head2 $t->empty
-
-Clears a table of all data to the level of not having been read
-
-=cut
-
-sub empty
-{
- my ($self) = @_;
- my (%keep);
-
- foreach (qw(INFILE LENGTH OFFSET CSUM PARENT))
- { $keep{" $_"} = 1; }
-
- map {delete $self->{$_} unless $keep{$_}} keys %$self;
- $self;
-}
-
-
-=head2 $t->release
-
-Releases ALL of the memory used by this table, and all of its component/child
-objects. This method is called automatically by
-'C<Font::TTF::Font-E<GT>release>' (so you don't have to call it yourself).
-
-B<NOTE>, that it is important that this method get called at some point prior
-to the actual destruction of the object. Internally, we track things in a
-structure that can result in circular references, and without calling
-'C<release()>' these will not properly get cleaned up by Perl. Once this
-method has been called, though, don't expect to be able to do anything with the
-C<Font::TTF::Table> object; it'll have B<no> internal state whatsoever.
-
-B<Developer note:> As part of the brute-force cleanup done here, this method
-will throw a warning message whenever unexpected key values are found within
-the C<Font::TTF::Table> object. This is done to help ensure that any
-unexpected and unfreed values are brought to your attention so that you can bug
-us to keep the module updated properly; otherwise the potential for memory
-leaks due to dangling circular references will exist.
-
-=cut
-
-sub release
-{
- my ($self) = @_;
-
-# delete stuff that we know we can, here
-
- my @tofree = map { delete $self->{$_} } keys %{$self};
-
- while (my $item = shift @tofree)
- {
- my $ref = ref($item);
- if (UNIVERSAL::can($item, 'release'))
- { $item->release(); }
- elsif ($ref eq 'ARRAY')
- { push( @tofree, @{$item} ); }
- elsif (UNIVERSAL::isa($ref, 'HASH'))
- { release($item); }
- }
-
-# check that everything has gone - it better had!
- foreach my $key (keys %{$self})
- { warn ref($self) . " still has '$key' key left after release.\n"; }
-}
-
-
-sub __dumpvar__
-{
- my ($self, $key) = @_;
-
- return ($key eq ' PARENT' ? '...parent...' : $self->{$key});
-}
-
-1;
-
-=head1 BUGS
-
-No known bugs
-
-=head1 AUTHOR
-
-Martin Hosken Martin_Hosken at sil.org. See L<Font::TTF::Font> for copyright and
-licensing.
-
-=cut
-
+package Font::TTF::Table;
+
+=head1 NAME
+
+Font::TTF::Table - Superclass for tables and used for tables we don't have a class for
+
+=head1 DESCRIPTION
+
+Looks after the purely table aspects of a TTF table, such as whether the table
+has been read before, locating the file pointer, etc. Also copies tables from
+input to output.
+
+=head1 INSTANCE VARIABLES
+
+Instance variables start with a space
+
+=over 4
+
+=item read
+
+Flag which indicates that the table has already been read from file.
+
+=item dat
+
+Allows the creation of unspecific tables. Data is simply output to any font
+file being created.
+
+=item INFILE
+
+The read file handle
+
+=item OFFSET
+
+Location of the file in the input file
+
+=item LENGTH
+
+Length in the input directory
+
+=item CSUM
+
+Checksum read from the input file's directory
+
+=item PARENT
+
+The L<Font::TTF::Font> that table is part of
+
+=back
+
+=head1 METHODS
+
+=cut
+
+use strict;
+use vars qw($VERSION);
+use Font::TTF::Utils;
+
+$VERSION = 0.0001;
+
+=head2 Font::TTF::Table->new(%parms)
+
+Creates a new table or subclass. Table instance variables are passed in
+at this point as an associative array.
+
+=cut
+
+sub new
+{
+ my ($class, %parms) = @_;
+ my ($self) = {};
+ my ($p);
+
+ $class = ref($class) || $class;
+ foreach $p (keys %parms)
+ { $self->{" $p"} = $parms{$p}; }
+ bless $self, $class;
+}
+
+
+=head2 $t->read
+
+Reads the table from the input file. Acts as a superclass to all true tables.
+This method marks the table as read and then just sets the input file pointer
+but does not read any data. If the table has already been read, then returns
+C<undef> else returns C<$self>
+
+=cut
+
+sub read
+{
+ my ($self) = @_;
+
+ return $self->read_dat if (ref($self) eq "Font::TTF::Table");
+ return undef if $self->{' read'};
+ $self->{' INFILE'}->seek($self->{' OFFSET'}, 0);
+ $self->{' read'} = 1;
+ $self;
+}
+
+
+=head2 $t->read_dat
+
+Reads the table into the C<dat> instance variable for those tables which don't
+know any better
+
+=cut
+
+sub read_dat
+{
+ my ($self) = @_;
+
+# can't just $self->read here otherwise those tables which start their read sub with
+# $self->read_dat are going to permanently loop
+ return undef if ($self->{' read'});
+# $self->{' read'} = 1; # Let read do this, now out will call us for subclasses
+ $self->{' INFILE'}->seek($self->{' OFFSET'}, 0);
+ $self->{' INFILE'}->read($self->{' dat'}, $self->{' LENGTH'});
+ $self;
+}
+
+=head2 $t->out($fh)
+
+Writes out the table to the font file. If there is anything in the
+C<data> instance variable then this is output, otherwise the data is copied
+from the input file to the output
+
+=cut
+
+sub out
+{
+ my ($self, $fh) = @_;
+ my ($dat, $i, $len, $count);
+
+ if (defined $self->{' dat'})
+ {
+ $fh->print($self->{' dat'});
+ return $self;
+ }
+
+ return undef unless defined $self->{' INFILE'};
+ $self->{' INFILE'}->seek($self->{' OFFSET'}, 0);
+ $len = $self->{' LENGTH'};
+ while ($len > 0)
+ {
+ $count = ($len > 4096) ? 4096 : $len;
+ $self->{' INFILE'}->read($dat, $count);
+ $fh->print($dat);
+ $len -= $count;
+ }
+ $self;
+}
+
+
+=head2 $t->out_xml($context)
+
+Outputs this table in XML format. The table is first read (if not already read) and then if
+there is no subclass, then the data is dumped as hex data
+
+=cut
+
+sub out_xml
+{
+ my ($self, $context, $depth) = @_;
+ my ($k);
+
+ if (ref($self) eq __PACKAGE__)
+ {
+ $self->read_dat;
+ Font::TTF::Utils::XML_hexdump($context, $depth, $self->{' dat'});
+ }
+ else
+ {
+ $self->read;
+ foreach $k (sort grep {$_ !~ m/^\s/o} keys %{$self})
+ {
+ $self->XML_element($context, $depth, $k, $self->{$k});
+ }
+ }
+ $self;
+}
+
+
+=head2 $t->XML_element
+
+Output a particular element based on its contents.
+
+=cut
+
+sub XML_element
+{
+ my ($self, $context, $depth, $k, $dat) = @_;
+ my ($fh) = $context->{'fh'};
+ my ($ndepth, $d);
+
+ return unless defined $dat;
+
+ if (!ref($dat))
+ {
+ $fh->printf("%s<%s>%s</%s>\n", $depth, $k, $dat, $k);
+ return $self;
+ }
+
+ $fh->printf("%s<%s>\n", $depth, $k);
+ $ndepth = $depth . $context->{'indent'};
+
+ if (ref($dat) eq 'SCALAR')
+ { $self->XML_element($context, $ndepth, 'scalar', $$dat); }
+ elsif (ref($dat) eq 'ARRAY')
+ {
+ foreach $d (@{$dat})
+ { $self->XML_element($context, $ndepth, 'elem', $d); }
+ }
+ elsif (ref($dat) eq 'HASH')
+ {
+ foreach $d (sort grep {$_ !~ m/^\s/o} keys %{$dat})
+ { $self->XML_element($context, $ndepth, $d, $dat->{$d}); }
+ }
+ else
+ {
+ $context->{'name'} = ref($dat);
+ $context->{'name'} =~ s/^.*://o;
+ $dat->out_xml($context, $ndepth);
+ }
+
+ $fh->printf("%s</%s>\n", $depth, $k);
+ $self;
+}
+
+
+=head2 $t->XML_end($context, $tag, %attrs)
+
+Handles the default type of <data> for those tables which aren't subclassed
+
+=cut
+
+sub XML_end
+{
+ my ($self, $context, $tag, %attrs) = @_;
+ my ($dat, $addr);
+
+ return undef unless ($tag eq 'data');
+ $dat = $context->{'text'};
+ $dat =~ s/([0-9a-f]{2})\s*/hex($1)/oig;
+ if (defined $attrs{'addr'})
+ { $addr = hex($attrs{'addr'}); }
+ else
+ { $addr = length($self->{' dat'}); }
+ substr($self->{' dat'}, $addr, length($dat)) = $dat;
+ return $context;
+}
+
+
+=head2 $t->dirty($val)
+
+This sets the dirty flag to the given value or 1 if no given value. It returns the
+value of the flag
+
+=cut
+
+sub dirty
+{
+ my ($self, $val) = @_;
+ my ($res) = $self->{' isDirty'};
+
+ $self->{' isDirty'} = defined $val ? $val : 1;
+ $res;
+}
+
+=head2 $t->update
+
+Each table knows how to update itself. This consists of doing whatever work
+is required to ensure that the memory version of the table is consistent
+and that other parameters in other tables have been updated accordingly.
+I.e. by the end of sending C<update> to all the tables, the memory version
+of the font should be entirely consistent.
+
+Some tables which do no work indicate to themselves the need to update
+themselves by setting isDirty above 1. This method resets that accordingly.
+
+=cut
+
+sub update
+{
+ my ($self) = @_;
+
+ if ($self->{' isDirty'})
+ {
+ $self->read;
+ $self->{' isDirty'} = 0;
+ return $self;
+ }
+ else
+ { return undef; }
+}
+
+
+=head2 $t->empty
+
+Clears a table of all data to the level of not having been read
+
+=cut
+
+sub empty
+{
+ my ($self) = @_;
+ my (%keep);
+
+ foreach (qw(INFILE LENGTH OFFSET CSUM PARENT))
+ { $keep{" $_"} = 1; }
+
+ map {delete $self->{$_} unless $keep{$_}} keys %$self;
+ $self;
+}
+
+
+=head2 $t->release
+
+Releases ALL of the memory used by this table, and all of its component/child
+objects. This method is called automatically by
+'C<Font::TTF::Font-E<GT>release>' (so you don't have to call it yourself).
+
+B<NOTE>, that it is important that this method get called at some point prior
+to the actual destruction of the object. Internally, we track things in a
+structure that can result in circular references, and without calling
+'C<release()>' these will not properly get cleaned up by Perl. Once this
+method has been called, though, don't expect to be able to do anything with the
+C<Font::TTF::Table> object; it'll have B<no> internal state whatsoever.
+
+B<Developer note:> As part of the brute-force cleanup done here, this method
+will throw a warning message whenever unexpected key values are found within
+the C<Font::TTF::Table> object. This is done to help ensure that any
+unexpected and unfreed values are brought to your attention so that you can bug
+us to keep the module updated properly; otherwise the potential for memory
+leaks due to dangling circular references will exist.
+
+=cut
+
+sub release
+{
+ my ($self) = @_;
+
+# delete stuff that we know we can, here
+
+ my @tofree = map { delete $self->{$_} } keys %{$self};
+
+ while (my $item = shift @tofree)
+ {
+ my $ref = ref($item);
+ if (UNIVERSAL::can($item, 'release'))
+ { $item->release(); }
+ elsif ($ref eq 'ARRAY')
+ { push( @tofree, @{$item} ); }
+ elsif (UNIVERSAL::isa($ref, 'HASH'))
+ { release($item); }
+ }
+
+# check that everything has gone - it better had!
+ foreach my $key (keys %{$self})
+ { warn ref($self) . " still has '$key' key left after release.\n"; }
+}
+
+
+sub __dumpvar__
+{
+ my ($self, $key) = @_;
+
+ return ($key eq ' PARENT' ? '...parent...' : $self->{$key});
+}
+
+1;
+
+=head1 BUGS
+
+No known bugs
+
+=head1 AUTHOR
+
+Martin Hosken Martin_Hosken at sil.org. See L<Font::TTF::Font> for copyright and
+licensing.
+
+=cut
+
Modified: packages/libfont-ttf-perl/trunk/lib/Font/TTF/Ttc.pm
===================================================================
--- packages/libfont-ttf-perl/trunk/lib/Font/TTF/Ttc.pm 2006-01-17 02:56:43 UTC (rev 1966)
+++ packages/libfont-ttf-perl/trunk/lib/Font/TTF/Ttc.pm 2006-01-17 03:07:20 UTC (rev 1967)
@@ -1,164 +1,164 @@
-package Font::TTF::Ttc;
-
-=head1 NAME
-
-Font::TTF::Ttc - Truetype Collection class
-
-=head1 DESCRIPTION
-
-A TrueType collection is a collection of TrueType fonts in one file in which
-tables may be shared between different directories. In order to support this,
-the TTC introduces the concept of a table being shared by different TrueType
-fonts. This begs the question of what should happen to the ' PARENT' property
-of a particular table. It is made to point to the first directory object which
-refers to it. It is therefore up to the application to sort out any confusion.
-Confusion only occurs if shared tables require access to non-shared tables.
-This should not happen since the shared tables are dealing with glyph
-information only and the private tables are dealing with encoding and glyph
-identification. Thus the general direction is from identification to glyph and
-not the other way around (at least not without knowledge of the particular
-context).
-
-=head1 INSTANCE VARIABLES
-
-The following instance variables are preceded by a space
-
-=over 4
-
-=item fname (P)
-
-Filename for this TrueType Collection
-
-=item INFILE (P)
-
-The filehandle of this collection
-
-=back
-
-The following instance variable does not start with a space
-
-=over 4
-
-=item directs
-
-An array of directories (Font::TTF::Font objects) for each sub-font in the directory
-
-=back
-
-=head1 METHODS
-
-=cut
-
-use strict;
-use vars qw($VERSION);
-
-use IO::File;
-
-$VERSION = 0.0001;
-
-=head2 Font::TTF::Ttc->open($fname)
-
-Opens and reads the given filename as a TrueType Collection. Reading a collection
-involves reading each of the directories which go to make up the collection.
-
-=cut
-
-sub open
-{
- my ($class, $fname) = @_;
- my ($self) = {};
- my ($fh);
-
- unless (ref($fname))
- {
- $fh = IO::File->new($fname) or return undef;
- binmode $fh;
- } else
- { $fh = $fname; }
-
- bless $self, $class;
- $self->{' INFILE'} = $fh;
- $self->{' fname'} = $fname;
- $fh->seek(0, 0);
- $self->read;
-}
-
-
-=head2 $c->read
-
-Reads a Collection by reading all the directories in the collection
-
-=cut
-
-sub read
-{
- my ($self) = @_;
- my ($fh) = $self->{' INFILE'};
- my ($dat, $ttc, $ver, $num, $i, $loc);
-
- $fh->read($dat, 12);
- ($ttc, $ver, $num) = unpack("A4N2", $dat);
-
- return undef unless $ttc eq "ttcf";
- $fh->read($dat, $num << 2);
- for ($i = 0; $i < $num; $i++)
- {
- $loc = unpack("N", substr($dat, $i << 2, 4));
- $self->{'directs'}[$i] = Font::TTF::Font->new('INFILE' => $fh,
- 'PARENT' => $self,
- 'OFFSET' => $loc) || return undef;
- }
- for ($i = 0; $i < $num; $i++)
- { $self->{'directs'}[$i]->read; }
- $self;
-}
-
-
-=head2 $c->find($direct, $name, $check, $off, $len)
-
-Hunts around to see if a table with the given characteristics of name, checksum,
-offset and length has been associated with a directory earlier in the list.
-Actually on checks the offset since no two tables can share the same offset in
-a TrueType font, collection or otherwise.
-
-=cut
-
-sub find
-{
- my ($self, $direct, $name, $check, $off, $len) = @_;
- my ($d);
-
- foreach $d (@{$self->{'directs'}})
- {
- return undef if $d eq $direct;
- next unless defined $d->{$name};
- return $d->{$name} if ($d->{$name}{' OFFSET'} == $off);
- }
- undef; # wierd that the font passed is not in the list!
-}
-
-
-=head2 $c->DESTROY
-
-Closees any opened files by us
-
-=cut
-
-sub DESTROY
-{
- my ($self) = @_;
- close ($self->{' INFILE'});
- undef;
-}
-
-=head1 BUGS
-
-No known bugs, but then not ever executed!
-
-=head1 AUTHOR
-
-Martin Hosken Martin_Hosken at sil.org. See L<Font::TTF::Font> for copyright and
-licensing.
-
-=cut
-
+package Font::TTF::Ttc;
+
+=head1 NAME
+
+Font::TTF::Ttc - Truetype Collection class
+
+=head1 DESCRIPTION
+
+A TrueType collection is a collection of TrueType fonts in one file in which
+tables may be shared between different directories. In order to support this,
+the TTC introduces the concept of a table being shared by different TrueType
+fonts. This begs the question of what should happen to the ' PARENT' property
+of a particular table. It is made to point to the first directory object which
+refers to it. It is therefore up to the application to sort out any confusion.
+Confusion only occurs if shared tables require access to non-shared tables.
+This should not happen since the shared tables are dealing with glyph
+information only and the private tables are dealing with encoding and glyph
+identification. Thus the general direction is from identification to glyph and
+not the other way around (at least not without knowledge of the particular
+context).
+
+=head1 INSTANCE VARIABLES
+
+The following instance variables are preceded by a space
+
+=over 4
+
+=item fname (P)
+
+Filename for this TrueType Collection
+
+=item INFILE (P)
+
+The filehandle of this collection
+
+=back
+
+The following instance variable does not start with a space
+
+=over 4
+
+=item directs
+
+An array of directories (Font::TTF::Font objects) for each sub-font in the directory
+
+=back
+
+=head1 METHODS
+
+=cut
+
+use strict;
+use vars qw($VERSION);
+
+use IO::File;
+
+$VERSION = 0.0001;
+
+=head2 Font::TTF::Ttc->open($fname)
+
+Opens and reads the given filename as a TrueType Collection. Reading a collection
+involves reading each of the directories which go to make up the collection.
+
+=cut
+
+sub open
+{
+ my ($class, $fname) = @_;
+ my ($self) = {};
+ my ($fh);
+
+ unless (ref($fname))
+ {
+ $fh = IO::File->new($fname) or return undef;
+ binmode $fh;
+ } else
+ { $fh = $fname; }
+
+ bless $self, $class;
+ $self->{' INFILE'} = $fh;
+ $self->{' fname'} = $fname;
+ $fh->seek(0, 0);
+ $self->read;
+}
+
+
+=head2 $c->read
+
+Reads a Collection by reading all the directories in the collection
+
+=cut
+
+sub read
+{
+ my ($self) = @_;
+ my ($fh) = $self->{' INFILE'};
+ my ($dat, $ttc, $ver, $num, $i, $loc);
+
+ $fh->read($dat, 12);
+ ($ttc, $ver, $num) = unpack("A4N2", $dat);
+
+ return undef unless $ttc eq "ttcf";
+ $fh->read($dat, $num << 2);
+ for ($i = 0; $i < $num; $i++)
+ {
+ $loc = unpack("N", substr($dat, $i << 2, 4));
+ $self->{'directs'}[$i] = Font::TTF::Font->new('INFILE' => $fh,
+ 'PARENT' => $self,
+ 'OFFSET' => $loc) || return undef;
+ }
+ for ($i = 0; $i < $num; $i++)
+ { $self->{'directs'}[$i]->read; }
+ $self;
+}
+
+
+=head2 $c->find($direct, $name, $check, $off, $len)
+
+Hunts around to see if a table with the given characteristics of name, checksum,
+offset and length has been associated with a directory earlier in the list.
+Actually on checks the offset since no two tables can share the same offset in
+a TrueType font, collection or otherwise.
+
+=cut
+
+sub find
+{
+ my ($self, $direct, $name, $check, $off, $len) = @_;
+ my ($d);
+
+ foreach $d (@{$self->{'directs'}})
+ {
+ return undef if $d eq $direct;
+ next unless defined $d->{$name};
+ return $d->{$name} if ($d->{$name}{' OFFSET'} == $off);
+ }
+ undef; # wierd that the font passed is not in the list!
+}
+
+
+=head2 $c->DESTROY
+
+Closees any opened files by us
+
+=cut
+
+sub DESTROY
+{
+ my ($self) = @_;
+ close ($self->{' INFILE'});
+ undef;
+}
+
+=head1 BUGS
+
+No known bugs, but then not ever executed!
+
+=head1 AUTHOR
+
+Martin Hosken Martin_Hosken at sil.org. See L<Font::TTF::Font> for copyright and
+licensing.
+
+=cut
+
Modified: packages/libfont-ttf-perl/trunk/lib/Font/TTF/Ttopen.pm
===================================================================
--- packages/libfont-ttf-perl/trunk/lib/Font/TTF/Ttopen.pm 2006-01-17 02:56:43 UTC (rev 1966)
+++ packages/libfont-ttf-perl/trunk/lib/Font/TTF/Ttopen.pm 2006-01-17 03:07:20 UTC (rev 1967)
@@ -1,1078 +1,1078 @@
-package Font::TTF::Ttopen;
-
-=head1 NAME
-
-Font::TTF::Ttopen - Opentype superclass for standard Opentype lookup based tables
-(GSUB and GPOS)
-
-=head1 DESCRIPTION
-
-Handles all the script, lang, feature, lookup stuff for a
-L<Font::TTF::Gsub>/L<Font::TTF::Gpos> table leaving the class specifics to the
-subclass
-
-=head1 INSTANCE VARIABLES
-
-The instance variables of an opentype table form a complex sub-module hierarchy.
-
-=over 4
-
-=item Version
-
-This contains the version of the table as a floating point number
-
-=item SCRIPTS
-
-The scripts list is a hash of script tags. Each script tag (of the form
-$t->{'SCRIPTS'}{$tag}) has information below it.
-
-=over 8
-
-=item OFFSET
-
-This variable is preceeded by a space and gives the offset from the start of the
-table (not the table section) to the script table for this script
-
-=item REFTAG
-
-This variable is preceded by a space and gives a corresponding script tag to this
-one such that the offsets in the file are the same. When writing, it is up to the
-caller to ensure that the REFTAGs are set correctly, since these will be used to
-assume that the scripts are identical. Note that REFTAG must refer to a script which
-has no REFTAG of its own.
-
-=item DEFAULT
-
-This corresponds to the default language for this script, if there is one, and
-contains the same information as an itemised language
-
-=item LANG_TAGS
-
-This contains an array of language tag strings (each 4 bytes) corresponding to
-the languages listed by this script
-
-=item $lang
-
-Each language is a hash containing its information:
-
-=over 12
-
-=item OFFSET
-
-This variable is preceeded by a a space and gives the offset from the start of
-the whole table to the language table for this language
-
-=item REFTAG
-
-This variable is preceded by a space and has the same function as for the script
-REFTAG, only for the languages within a script.
-
-=item RE-ORDER
-
-This indicates re-ordering information, and has not been set. The value should
-always be 0.
-
-=item DEFAULT
-
-This holds the index of the default feature, if there is one, or -1 otherwise.
-
-=item FEATURES
-
-This is an array of feature indices which index into the FEATURES instance
-variable of the table
-
-=back
-
-=back
-
-=item FEATURES
-
-The features section of instance variables corresponds to the feature table in
-the opentype table.
-
-=over 8
-
-=item FEAT_TAGS
-
-This array gives the ordered list of feature tags for this table. It is used during
-reading and writing for converting between feature index and feature tag.
-
-=back
-
-The rest of the FEATURES variable is itself a hash based on the feature tag for
-each feature. Each feature has the following structure:
-
-=over 8
-
-=item OFFSET
-
-This attribute is preceeded by a space and gives the offset relative to the start of the whole
-table of this particular feature.
-
-=item PARMS
-
-This is an unused offset to the parameters for each feature
-
-=item LOOKUPS
-
-This is an array containing indices to lookups in the LOOKUP instance variable of the table
-
-=item INDEX
-
-This gives the feature index for this feature and is used during reading and writing for
-converting between feature tag and feature index.
-
-=back
-
-=item LOOKUP
-
-This variable is an array of lookups in order and is indexed via the features of a language of a
-script. Each lookup contains subtables and other information:
-
-=over 8
-
-=item OFFSET
-
-This name is preceeded by a space and contains the offset from the start of the table to this
-particular lookup
-
-=item TYPE
-
-This is a subclass specific type for a lookup. It stipulates the type of lookup and hence subtables
-within the lookup
-
-=item FLAG
-
-Holds the lookup flag bits
-
-=item SUB
-
-This holds an array of subtables which are subclass specific. Each subtable must have
-an OFFSET. The other variables described here are an abstraction used in both the
-GSUB and GPOS tables which are the target subclasses of this class.
-
-=over 12
-
-=item OFFSET
-
-This is preceeded by a space and gives the offset relative to the start of the table for this
-subtable
-
-=item FORMAT
-
-Gives the sub-table sub format for this GSUB subtable. It is assumed that this
-value is correct when it comes time to write the subtable.
-
-=item COVERAGE
-
-Most lookups consist of a coverage table corresponding to the first
-glyph to match. The offset of this coverage table is stored here and the coverage
-table looked up against the GSUB table proper. There are two lookups
-without this initial coverage table which is used to index into the RULES array.
-These lookups have one element in the RULES array which is used for the whole
-match.
-
-=item RULES
-
-The rules are a complex array. Each element of the array corresponds to an
-element in the coverage table (governed by the coverage index). If there is
-no coverage table, then there is considered to be only one element in the rules
-array. Each element of the array is itself an array corresponding to the
-possibly multiple string matches which may follow the initial glyph. Each
-element of this array is a hash with fixed keys corresponding to information
-needed to match a glyph string or act upon it. Thus the RULES element is an
-array of arrays of hashes which contain the following keys:
-
-=over 16
-
-=item MATCH
-
-This contains a sequence of elements held as an array. The elements may be
-glyph ids (gid), class ids (cids), or offsets to coverage tables. Each element
-corresponds to one glyph in the glyph string. See MATCH_TYPE for details of
-how the different element types are marked.
-
-=item PRE
-
-This array holds the sequence of elements preceeding the first match element
-and has the same form as the MATCH array.
-
-=item POST
-
-This array holds the sequence of elements to be tested for following the match
-string and is of the same form as the MATCH array.
-
-=item ACTION
-
-This array holds information regarding what should be done if a match is found.
-The array may either hold glyph ids (which are used to replace or insert or
-whatever glyphs in the glyph string) or 2 element arrays consisting of:
-
-=over 20
-
-=item OFFSET
-
-Offset from the start of the matched string that the lookup should start at
-when processing the substring.
-
-=item LOOKUP_INDEX
-
-The index to a lookup to be acted upon on the match string.
-
-=back
-
-=back
-
-=back
-
-=back
-
-=item CLASS
-
-For those lookups which use class categories rather than glyph ids for matching
-this is the offset to the class definition used to categories glyphs in the
-match string.
-
-=item PRE_CLASS
-
-This is the offset to the class definition for the before match glyphs
-
-=item POST_CLASS
-
-This is the offset to the class definition for the after match glyphs.
-
-=item ACTION_TYPE
-
-This string holds the type of information held in the ACTION variable of a RULE.
-It is subclass specific.
-
-=item MATCH_TYPE
-
-This holds the type of information in the MATCH array of a RULE. This is subclass
-specific.
-
-=item ADJUST
-
-This corresponds to a single action for all items in a coverage table. The meaning
-is subclass specific.
-
-=item CACHE
-
-This key starts with a space
-
-A hash of other tables (such as coverage tables, classes, anchors, device tables)
-based on the offset given in the subtable to that other information.
-Note that the documentation is particularly
-unhelpful here in that such tables are given as offsets relative to the
-beginning of the subtable not the whole GSUB table. This includes those items which
-are stored relative to another base within the subtable.
-
-=back
-
-
-=head1 METHODS
-
-=cut
-
-use Font::TTF::Table;
-use Font::TTF::Utils;
-use Font::TTF::Coverage;
-use strict;
-use vars qw(@ISA);
-
- at ISA = qw(Font::TTF::Table);
-
-=head2 $t->read
-
-Reads the table passing control to the subclass to handle the subtable specifics
-
-=cut
-
-sub read
-{
- my ($self) = @_;
- my ($dat, $i, $l, $oScript, $oFeat, $oLook, $tag, $nScript, $off, $dLang, $nLang, $lTag);
- my ($nFeat, $nLook, $nSub, $j, $temp);
- my ($fh) = $self->{' INFILE'};
- my ($moff) = $self->{' OFFSET'};
-
- $self->SUPER::read or return $self;
- $fh->read($dat, 10);
- ($self->{'Version'}, $oScript, $oFeat, $oLook) = TTF_Unpack("fSSS", $dat);
-
-# read features first so that in the script/lang hierarchy we can use feature tags
-
- $fh->seek($moff + $oFeat, 0);
- $fh->read($dat, 2);
- $nFeat = unpack("n", $dat);
- $self->{'FEATURES'} = {};
- $l = $self->{'FEATURES'};
- $fh->read($dat, 6 * $nFeat);
- for ($i = 0; $i < $nFeat; $i++)
- {
- ($tag, $off) = unpack("a4n", substr($dat, $i * 6, 6));
- while (defined $l->{$tag})
- {
- if ($tag =~ m/(.*?)\s_(\d+)$/o)
- { $tag = $1 . " _" . ($2 + 1); }
- else
- { $tag .= " _0"; }
- }
- $l->{$tag}{' OFFSET'} = $off + $oFeat;
- $l->{$tag}{'INDEX'} = $i;
- push (@{$l->{'FEAT_TAGS'}}, $tag);
- }
-
- foreach $tag (grep {length($_) == 4} keys %$l)
- {
- $fh->seek($moff + $l->{$tag}{' OFFSET'}, 0);
- $fh->read($dat, 4);
- ($l->{$tag}{'PARMS'}, $nLook) = unpack("n2", $dat);
- $fh->read($dat, $nLook * 2);
- $l->{$tag}{'LOOKUPS'} = [unpack("n*", $dat)];
- }
-
-# Now the script/lang hierarchy
-
- $fh->seek($moff + $oScript, 0);
- $fh->read($dat, 2);
- $nScript = unpack("n", $dat);
- $self->{'SCRIPTS'} = {};
- $l = $self->{'SCRIPTS'};
- $fh->read($dat, 6 * $nScript);
- for ($i = 0; $i < $nScript; $i++)
- {
- ($tag, $off) = unpack("a4n", substr($dat, $i * 6, 6));
- $off += $oScript;
- foreach (keys %$l)
- { $l->{$tag}{' REFTAG'} = $_ if ($l->{$_}{' OFFSET'} == $off
- && !defined $l->{$_}{' REFTAG'}); }
- $l->{$tag}{' OFFSET'} = $off;
- }
-
- foreach $tag (keys %$l)
- {
- next if ($l->{$tag}{' REFTAG'});
- $fh->seek($moff + $l->{$tag}{' OFFSET'}, 0);
- $fh->read($dat, 4);
- ($dLang, $nLang) = unpack("n2", $dat);
- $l->{$tag}{'DEFAULT'}{' OFFSET'} =
- $dLang + $l->{$tag}{' OFFSET'} if $dLang;
- $fh->read($dat, 6 * $nLang);
- for ($i = 0; $i < $nLang; $i++)
- {
- ($lTag, $off) = unpack("a4n", substr($dat, $i * 6, 6));
- $off += $l->{$tag}{' OFFSET'};
- $l->{$tag}{$lTag}{' OFFSET'} = $off;
- foreach (@{$l->{$tag}{'LANG_TAGS'}})
- { $l->{$tag}{$lTag}{' REFTAG'} = $_ if ($l->{$tag}{$_}{' OFFSET'} == $off
- && !$l->{$tag}{$_}{' REFTAG'}); }
- push (@{$l->{$tag}{'LANG_TAGS'}}, $lTag);
- }
- foreach $lTag (@{$l->{$tag}{'LANG_TAGS'}}, 'DEFAULT')
- {
- next unless defined $l->{$tag}{$lTag};
- next if ($l->{$tag}{$lTag}{' REFTAG'});
- $fh->seek($moff + $l->{$tag}{$lTag}{' OFFSET'}, 0);
- $fh->read($dat, 6);
- ($l->{$tag}{$lTag}{'RE-ORDER'}, $l->{$tag}{$lTag}{'DEFAULT'}, $nFeat)
- = unpack("n3", $dat);
- $fh->read($dat, $nFeat * 2);
- $l->{$tag}{$lTag}{'FEATURES'} = [map {$self->{'FEATURES'}{'FEAT_TAGS'}[$_]} unpack("n*", $dat)];
- }
- foreach $lTag (@{$l->{$tag}{'LANG_TAGS'}}, 'DEFAULT')
- {
- next unless $l->{$tag}{$lTag}{' REFTAG'};
- $temp = $l->{$tag}{$lTag}{' REFTAG'};
- $l->{$tag}{$lTag} = ©($l->{$tag}{$temp});
- $l->{$tag}{$lTag}{' REFTAG'} = $temp;
- }
- }
- foreach $tag (keys %$l)
- {
- next unless $l->{$tag}{' REFTAG'};
- $temp = $l->{$tag}{' REFTAG'};
- $l->{$tag} = ©($l->{$temp});
- $l->{$tag}{' REFTAG'} = $temp;
- }
-
-# And finally the lookups
-
- $fh->seek($moff + $oLook, 0);
- $fh->read($dat, 2);
- $nLook = unpack("n", $dat);
- $fh->read($dat, $nLook * 2);
- $i = 0;
- map { $self->{'LOOKUP'}[$i++]{' OFFSET'} = $_; } unpack("n*", $dat);
-
- for ($i = 0; $i < $nLook; $i++)
- {
- $l = $self->{'LOOKUP'}[$i];
- $fh->seek($l->{' OFFSET'} + $moff + $oLook, 0);
- $fh->read($dat, 6);
- ($l->{'TYPE'}, $l->{'FLAG'}, $nSub) = unpack("n3", $dat);
- $fh->read($dat, $nSub * 2);
- $j = 0;
- map { $l->{'SUB'}[$j]{' OFFSET'} = $_; } unpack("n*", $dat);
- for ($j = 0; $j < $nSub; $j++)
- {
- $fh->seek($moff + $oLook + $l->{' OFFSET'} + $l->{'SUB'}[$j]{' OFFSET'}, 0);
- $self->read_sub($fh, $l, $j);
- }
- }
- return $self;
-}
-
-=head2 $t->read_sub($fh, $lookup, $index)
-
-This stub is to allow subclasses to read subtables of lookups in a table specific manner. A
-reference to the lookup is passed in along with the subtable index. The file is located at the
-start of the subtable to be read
-
-=cut
-
-sub read_sub
-{ }
-
-
-=head2 $t->extension()
-
-Returns the lookup number for the extension table that allows access to 32-bit offsets.
-
-=cut
-
-sub extension
-{ }
-
-
-=head2 $t->out($fh)
-
-Writes this Opentype table to the output calling $t->out_sub for each sub table
-at the appropriate point in the output. The assumption is that on entry the
-number of scripts, languages, features, lookups, etc. are all resolved and
-the relationships fixed. This includes a script's LANG_TAGS list and that all
-scripts and languages in their respective dictionaries either have a REFTAG or contain
-real data.
-
-=cut
-
-sub out
-{
- my ($self, $fh) = @_;
- my ($i, $j, $base, $off, $tag, $t, $l, $lTag, $oScript, @script, @tags);
- my ($end, $nTags, @offs, $oFeat, $oLook, $nSub, $nSubs, $big);
-
- return $self->SUPER::out($fh) unless $self->{' read'};
-
-# First sort the features
- $i = 0;
- $self->{'FEATURES'}{'FEAT_TAGS'} = [sort grep {length($_) == 4 || m/\s_\d+$/o} %{$self->{'FEATURES'}}]
- if (!defined $self->{'FEATURES'}{'FEAT_TAGS'});
- foreach $t (@{$self->{'FEATURES'}{'FEAT_TAGS'}})
- { $self->{'FEATURES'}{$t}{'INDEX'} = $i++; }
-
- $base = $fh->tell();
- $fh->print(TTF_Pack("f", $self->{'Version'}));
- $fh->print(pack("n3", 10, 0, 0));
- $oScript = $fh->tell() - $base;
- @script = sort grep {length($_) == 4} keys %{$self->{'SCRIPTS'}};
- $fh->print(pack("n", $#script + 1));
- foreach $t (@script)
- { $fh->print(pack("a4n", $t, 0)); }
-
- $end = $fh->tell();
- foreach $t (@script)
- {
- $fh->seek($end, 0);
- $tag = $self->{'SCRIPTS'}{$t};
- next if ($tag->{' REFTAG'});
- $tag->{' OFFSET'} = tell($fh) - $base - $oScript;
- $fh->print(pack("n2", 0, $#{$tag->{'LANG_TAGS'}} + 1));
- foreach $lTag (sort @{$tag->{'LANG_TAGS'}})
- { $fh->print(pack("a4n", $lTag, 0)); }
- foreach $lTag (@{$tag->{'LANG_TAGS'}}, 'DEFAULT')
- {
- my ($def);
- $l = $tag->{$lTag};
- next if (!defined $l || $l->{' REFTAG'} ne '');
- $l->{' OFFSET'} = tell($fh) - $base - $oScript - $tag->{' OFFSET'};
- if (defined $l->{'DEFAULT'})
-# { $def = $self->{'FEATURES'}{$l->{'FEATURES'}[$l->{'DEFAULT'}]}{'INDEX'}; }
- { $def = $l->{'DEFAULT'}; }
- else
- { $def = -1; }
- $fh->print(pack("n*", $l->{'RE_ORDER'}, $def, $#{$l->{'FEATURES'}} + 1,
- map {$self->{'FEATURES'}{$_}{'INDEX'}} @{$l->{'FEATURES'}}));
- }
- $end = $fh->tell();
- if ($tag->{'DEFAULT'}{' REFTAG'} || defined $tag->{'DEFAULT'}{'FEATURES'})
- {
- $fh->seek($base + $oScript + $tag->{' OFFSET'}, 0);
- $off = $tag->{'DEFAULT'}{' REFTAG'} ?
- $tag->{$tag->{'DEFAULT'}{' REFTAG'}}{' OFFSET'} :
- $tag->{'DEFAULT'}{' OFFSET'};
- $fh->print(pack("n", $off));
- }
- $fh->seek($base + $oScript + $tag->{' OFFSET'} + 4, 0);
- foreach (sort @{$tag->{'LANG_TAGS'}})
- {
- $off = $tag->{$_}{' REFTAG'} ? $tag->{$tag->{$_}{' REFTAG'}}{' OFFSET'} :
- $tag->{$_}{' OFFSET'};
- $fh->print(pack("a4n", $_, $off));
- }
- }
- $fh->seek($base + $oScript + 2, 0);
- foreach $t (@script)
- {
- $tag = $self->{'SCRIPTS'}{$t};
- $off = $tag->{' REFTAG'} ? $tag->{$tag->{' REFTAG'}}{' OFFSET'} : $tag->{' OFFSET'};
- $fh->print(pack("a4n", $t, $off));
- }
-
- $fh->seek($end, 0);
- $oFeat = $end - $base;
- $nTags = $#{$self->{'FEATURES'}{'FEAT_TAGS'}} + 1;
- $fh->print(pack("n", $nTags));
- $fh->print(pack("a4n", " ", 0) x $nTags);
-
- foreach $t (@{$self->{'FEATURES'}{'FEAT_TAGS'}})
- {
- $tag = $self->{'FEATURES'}{$t};
- $tag->{' OFFSET'} = tell($fh) - $base - $oFeat;
- $fh->print(pack("n*", 0, $#{$tag->{'LOOKUPS'}} + 1, @{$tag->{'LOOKUPS'}}));
- }
- $end = $fh->tell();
- $fh->seek($oFeat + $base + 2, 0);
- foreach $t (@{$self->{'FEATURES'}{'FEAT_TAGS'}})
- { $fh->print(pack("a4n", $t, $self->{'FEATURES'}{$t}{' OFFSET'})); }
-
- undef $big;
- $fh->seek($end, 0);
- $oLook = $end - $base;
-
- # Start Lookup List Table
- $nTags = $#{$self->{'LOOKUP'}} + 1;
- $fh->print(pack("n", $nTags));
- $fh->print(pack("n", 0) x $nTags);
- $end = $fh->tell(); # end of LookupListTable = start of Lookups
- foreach $tag (@{$self->{'LOOKUP'}})
- { $nSubs += $self->num_sub($tag); }
- for ($i = 0; $i < $nTags; $i++)
- {
- $fh->seek($end, 0);
- $tag = $self->{'LOOKUP'}[$i];
- $off = $end - $base - $oLook; # BH 2004-03-04
- # Is there room, from the start of this i'th lookup, for this and the remaining
- # lookups to be wrapped in extension lookups?
- if (!defined $big && $off + ($nTags - $i) * 6 + $nSubs * 10 > 65535) # BH 2004-03-04
- {
- # Not enough room -- need to start an extension!
- my ($k, $ext);
- $ext = $self->extension();
- # Must turn previous lookup into the first extension
- $i--;
- $tag = $self->{'LOOKUP'}[$i];
- $end = $tag->{' OFFSET'} + $base + $oLook;
- $fh->seek($end, 0);
- $big = $i;
- # For this and the remaining lookups, build extensions lookups
- for ($j = $i; $j < $nTags; $j++)
- {
- $tag = $self->{'LOOKUP'}[$j];
- $nSub = $self->num_sub($tag);
- $fh->print(pack("nnn", $ext, $tag->{'FLAG'}, $nSub));
- $fh->print(pack("n*", map {$_ * 8 + 6 + $nSub * 2} (0 .. $nSub-1))); # BH 2004-03-04
- $tag->{' EXT_OFFSET'} = $fh->tell(); # = first extension lookup subtable
- $tag->{' OFFSET'} = $tag->{' EXT_OFFSET'} - $nSub * 2 - 6 - $base - $oLook; # offset to this extension lookup
- for ($k = 0; $k < $nSub; $k++)
- { $fh->print(pack('nnN', 1, $tag->{'TYPE'}, 0)); }
- }
-
- $tag = $self->{'LOOKUP'}[$i];
- # Leave file positioned after all the extension lookups -- where the referenced lookups will start.
- }
- $tag->{' OFFSET'} = $off unless defined $big; # BH 2004-03-04
- $nSub = $self->num_sub($tag);
- if (!defined $big)
- {
- $fh->print(pack("nnn", $tag->{'TYPE'}, $tag->{'FLAG'}, $nSub));
- $fh->print(pack("n", 0) x $nSub);
- }
- else
- { $end = $tag->{' EXT_OFFSET'}; }
- @offs = ();
- for ($j = 0; $j < $nSub; $j++)
- {
- push(@offs, tell($fh) - $end);
- $self->out_sub($fh, $tag, $j);
- }
- $end = $fh->tell();
- if (!defined $big)
- {
- $fh->seek($tag->{' OFFSET'} + $base + $oLook + 6, 0);
- $fh->print(pack("n*", @offs));
- }
- else
- {
- $fh->seek($tag->{' EXT_OFFSET'}, 0);
- for ($j = 0; $j < $nSub; $j++)
- { $fh->print(pack('nnN', 1, $tag->{'TYPE'}, $offs[$j] - $j * 8)); }
- }
- }
- $fh->seek($oLook + $base + 2, 0);
- $fh->print(pack("n*", map {$self->{'LOOKUP'}[$_]{' OFFSET'}} (0 .. $nTags - 1)));
- $fh->seek($base + 6, 0);
- $fh->print(pack('n2', $oFeat, $oLook));
- $fh->seek($end, 0);
- $self;
-}
-
-
-=head2 $t->num_sub($lookup)
-
-Asks the subclass to count the number of subtables for a particular lookup and to
-return that value. Used in out().
-
-=cut
-
-sub num_sub
-{
- my ($self, $lookup) = @_;
-
- return $#{$lookup->{'SUB'}} + 1;
-}
-
-
-=head2 $t->out_sub($fh, $lookup, $index)
-
-This stub is to allow subclasses to output subtables of lookups in a table specific manner. A
-reference to the lookup is passed in along with the subtable index. The file is located at the
-start of the subtable to be output
-
-=cut
-
-sub out_sub
-{ }
-
-
-=head1 Internal Functions & Methods
-
-Most of these methods are used by subclasses for handling such things as coverage
-tables.
-
-=head2 copy($ref)
-
-Internal function to copy the top level of a dictionary to create a new dictionary.
-Only the top level is copied.
-
-=cut
-
-sub copy
-{
- my ($ref) = @_;
- my ($res) = {};
-
- foreach (keys %$ref)
- { $res->{$_} = $ref->{$_}; }
- $res;
-}
-
-
-=head2 $t->read_cover($cover_offset, $lookup_loc, $lookup, $fh, $is_cover)
-
-Reads a coverage table and stores the results in $lookup->{' CACHE'}, that is, if
-it hasn't been read already.
-
-=cut
-
-sub read_cover
-{
- my ($self, $offset, $base, $lookup, $fh, $is_cover) = @_;
- my ($loc) = $fh->tell();
- my ($cover, $str);
-
- return undef unless $offset;
- $str = sprintf("%X", $base + $offset);
- return $lookup->{' CACHE'}{$str} if defined $lookup->{' CACHE'}{$str};
- $fh->seek($base + $offset, 0);
- $cover = Font::TTF::Coverage->new($is_cover)->read($fh);
- $fh->seek($loc, 0);
- $lookup->{' CACHE'}{$str} = $cover;
- return $cover;
-}
-
-
-=head2 ref_cache($obj, $cache, $offset)
-
-Internal function to keep track of the local positioning of subobjects such as
-coverage and class definition tables, and their offsets.
-What happens is that the cache is a hash of
-sub objects indexed by the reference (using a string mashing of the
-reference name which is valid for the duration of the reference) and holds a
-list of locations in the output string which should be filled in with the
-offset to the sub object when the final string is output in out_final.
-
-Uses tricks for Tie::Refhash
-
-=cut
-
-sub ref_cache
-{
- my ($obj, $cache, $offset) = @_;
-
- return 0 unless defined $obj;
- $cache->{"$obj"}[0] = $obj unless defined $cache->{"$obj"};
- push (@{$cache->{"$obj"}[1]}, $offset);
- return 0;
-}
-
-
-=head2 out_final($fh, $out, $cache_list, $state)
-
-Internal function to actually output everything to the file handle given that
-now we know the offset to the first sub object to be output and which sub objects
-are to be output and what locations need to be updated, we can now
-generate everything. $cache_list is an array of two element arrays. The first element
-is a cache object, the second is an offset to be subtracted from each reference
-to that object made in the cache.
-
-If $state is 1, then the output is not sent to the filehandle and the return value
-is the string to be output. If $state is absent or 0 then output is not limited
-by storing in a string first and the return value is "";
-
-=cut
-
-sub out_final
-{
- my ($fh, $out, $cache_list, $state) = @_;
- my ($len) = length($out);
- my ($base_loc) = $state ? 0 : $fh->tell();
- my ($loc, $t, $r, $s, $master_cache, $offs, $str);
-
- $fh->print($out) unless $state; # first output the current attempt
- foreach $r (@$cache_list)
- {
- $offs = $r->[1];
- foreach $t (sort keys %{$r->[0]})
- {
- $str = "$t";
- if (!defined $master_cache->{$str})
- {
- $master_cache->{$str} = ($state ? length($out) : $fh->tell())
- - $base_loc;
- if ($state)
- { $out .= $r->[0]{$str}[0]->out($fh, 1); }
- else
- { $r->[0]{$str}[0]->out($fh, 0); }
- }
- foreach $s (@{$r->[0]{$str}[1]})
- { substr($out, $s, 2) = pack('n', $master_cache->{$str} - $offs); }
- }
- }
- if ($state)
- { return $out; }
- else
- {
- $loc = $fh->tell();
- $fh->seek($base_loc, 0);
- $fh->print($out); # the corrected version
- $fh->seek($loc, 0);
- }
-}
-
-
-=head2 $self->read_context($lookup, $fh, $type, $fmt, $cover, $count, $loc)
-
-Internal method to read context (simple and chaining context) lookup subtables for
-the GSUB and GPOS table types. The assumed values for $type correspond to those
-for GSUB, so GPOS should adjust the values upon calling.
-
-=cut
-
-sub read_context
-{
- my ($self, $lookup, $fh, $type, $fmt, $cover, $count, $loc) = @_;
- my ($dat, $i, $s, $t, @subst, @srec, $mcount, $scount);
-
- if ($type == 5 && $fmt < 3)
- {
- if ($fmt == 2)
- {
- $fh->read($dat, 2);
- $lookup->{'CLASS'} = $self->read_cover($count, $loc, $lookup, $fh, 0);
- $count = TTF_Unpack('S', $dat);
- }
- $fh->read($dat, $count << 1);
- foreach $s (TTF_Unpack('S*', $dat))
- {
- if ($s == 0)
- {
- push (@{$lookup->{'RULES'}}, []);
- next;
- }
- @subst = ();
- $fh->seek($loc + $s, 0);
- $fh->read($dat, 2);
- $t = TTF_Unpack('S', $dat);
- $fh->read($dat, $t << 1);
- foreach $t (TTF_Unpack('S*', $dat))
- {
- $fh->seek($loc + $s + $t, 0);
- @srec = ();
- $fh->read($dat, 4);
- ($mcount, $scount) = TTF_Unpack('S2', $dat);
- $mcount--;
- $fh->read($dat, ($mcount << 1) + ($scount << 2));
- for ($i = 0; $i < $scount; $i++)
- { push (@srec, [TTF_Unpack('S2', substr($dat,
- ($mcount << 1) + ($i << 2), 4))]); }
- push (@subst, {'ACTION' => [@srec],
- 'MATCH' => [TTF_Unpack('S*',
- substr($dat, 0, $mcount << 1))]});
- }
- push (@{$lookup->{'RULES'}}, [@subst]);
- }
- $lookup->{'ACTION_TYPE'} = 'l';
- $lookup->{'MATCH_TYPE'} = ($fmt == 2 ? 'c' : 'g');
- } elsif ($type == 5 && $fmt == 3)
- {
- $fh->read($dat, ($cover << 1) + ($count << 2));
- @subst = (); @srec = ();
- for ($i = 0; $i < $cover; $i++)
- { push (@subst, $self->read_cover(TTF_Unpack('S', substr($dat, $i << 1, 2)),
- $loc, $lookup, $fh, 1)); }
- for ($i = 0; $i < $count; $i++)
- { push (@srec, [TTF_Unpack('S2', substr($dat, ($count << 1) + ($i << 2), 4))]); }
- $lookup->{'RULES'} = [[{'ACTION' => [@srec], 'MATCH' => [@subst]}]];
- $lookup->{'ACTION_TYPE'} = 'l';
- $lookup->{'MATCH_TYPE'} = 'o';
- } elsif ($type == 6 && $fmt < 3)
- {
- if ($fmt == 2)
- {
- $fh->read($dat, 6);
- $lookup->{'PRE_CLASS'} = $self->read_cover($count, $loc, $lookup, $fh, 0) if $count;
- ($i, $mcount, $count) = TTF_Unpack('S3', $dat); # messy: 2 classes & count
- $lookup->{'CLASS'} = $self->read_cover($i, $loc, $lookup, $fh, 0) if $i;
- $lookup->{'POST_CLASS'} = $self->read_cover($mcount, $loc, $lookup, $fh, 0) if $mcount;
- }
- $fh->read($dat, $count << 1);
- foreach $s (TTF_Unpack('S*', $dat))
- {
- if ($s == 0)
- {
- push (@{$lookup->{'RULES'}}, []);
- next;
- }
- @subst = ();
- $fh->seek($loc + $s, 0);
- $fh->read($dat, 2);
- $t = TTF_Unpack('S', $dat);
- $fh->read($dat, $t << 1);
- foreach $i (TTF_Unpack('S*', $dat))
- {
- $fh->seek($loc + $s + $i, 0);
- @srec = ();
- $t = {};
- $fh->read($dat, 2);
- $mcount = TTF_Unpack('S', $dat);
- if ($mcount > 0)
- {
- $fh->read($dat, $mcount << 1);
- $t->{'PRE'} = [TTF_Unpack('S*', $dat)];
- }
- $fh->read($dat, 2);
- $mcount = TTF_Unpack('S', $dat);
- if ($mcount > 1)
- {
- $fh->read($dat, ($mcount - 1) << 1);
- $t->{'MATCH'} = [TTF_Unpack('S*', $dat)];
- }
- $fh->read($dat, 2);
- $mcount = TTF_Unpack('S', $dat);
- if ($mcount > 0)
- {
- $fh->read($dat, $mcount << 1);
- $t->{'POST'} = [TTF_Unpack('S*', $dat)];
- }
- $fh->read($dat, 2);
- $scount = TTF_Unpack('S', $dat);
- $fh->read($dat, $scount << 2);
- for ($i = 0; $i < $scount; $i++)
- { push (@srec, [TTF_Unpack('S2', substr($dat, $i << 2))]); }
- $t->{'ACTION'} = [@srec];
- push (@subst, $t);
- }
- push (@{$lookup->{'RULES'}}, [@subst]);
- }
- $lookup->{'ACTION_TYPE'} = 'l';
- $lookup->{'MATCH_TYPE'} = ($fmt == 2 ? 'c' : 'g');
- } elsif ($type == 6 && $fmt == 3)
- {
- $t = {};
- unless ($cover == 0)
- {
- @subst = ();
- $fh->read($dat, $cover << 1);
- foreach $s (TTF_Unpack('S*', $dat))
- { push(@subst, $self->read_cover($s, $loc, $lookup, $fh, 1)); }
- $t->{'PRE'} = [@subst];
- }
- $fh->read($dat, 2);
- $count = TTF_Unpack('S', $dat);
- unless ($count == 0)
- {
- @subst = ();
- $fh->read($dat, $count << 1);
- foreach $s (TTF_Unpack('S*', $dat))
- { push(@subst, $self->read_cover($s, $loc, $lookup, $fh, 1)); }
- $t->{'MATCH'} = [@subst];
- }
- $fh->read($dat, 2);
- $count = TTF_Unpack('S', $dat);
- unless ($count == 0)
- {
- @subst = ();
- $fh->read($dat, $count << 1);
- foreach $s (TTF_Unpack('S*', $dat))
- { push(@subst, $self->read_cover($s, $loc, $lookup, $fh, 1)); }
- $t->{'POST'} = [@subst];
- }
- $fh->read($dat, 2);
- $count = TTF_Unpack('S', $dat);
- @subst = ();
- $fh->read($dat, $count << 2);
- for ($i = 0; $i < $count; $i++)
- { push (@subst, [TTF_Unpack('S2', substr($dat, $i << 2, 4))]); }
- $t->{'ACTION'} = [@subst];
- $lookup->{'RULES'} = [[$t]];
- $lookup->{'ACTION_TYPE'} = 'l';
- $lookup->{'MATCH_TYPE'} = 'o';
- }
- $lookup;
-}
-
-
-=head2 $self->out_context($lookup, $fh, $type, $fmt, $ctables, $out, $num)
-
-Provides shared behaviour between GSUB and GPOS tables during output for context
-(chained and simple) rules. In addition, support is provided here for type 4 GSUB
-tables, which are not used in GPOS. The value for $type corresponds to the type
-in a GSUB table so calling from GPOS should adjust the value accordingly.
-
-=cut
-
-sub out_context
-{
- my ($self, $lookup, $fh, $type, $fmt, $ctables, $out, $num) = @_;
- my ($offc, $offd, $i, $j, $r, $t, $numd);
-
- if (($type == 4 || $type == 5 || $type == 6) && ($fmt == 1 || $fmt == 2))
- {
- my ($base_off);
-
- if ($fmt == 1)
- {
- $out = pack("nnn", $fmt, Font::TTF::Ttopen::ref_cache($lookup->{'COVERAGE'}, $ctables, 2),
- $num);
- $base_off = 6;
- } elsif ($type == 5)
- {
- $out = pack("nnnn", $fmt, Font::TTF::Ttopen::ref_cache($lookup->{'COVERAGE'}, $ctables, 2),
- Font::TTF::Ttopen::ref_cache($lookup->{'CLASS'}, $ctables, 4), $num);
- $base_off = 8;
- } elsif ($type == 6)
- {
- $out = pack("n6", $fmt, Font::TTF::Ttopen::ref_cache($lookup->{'COVERAGE'}, $ctables, 2),
- Font::TTF::Ttopen::ref_cache($lookup->{'PRE_CLASS'}, $ctables, 4),
- Font::TTF::Ttopen::ref_cache($lookup->{'CLASS'}, $ctables, 6),
- Font::TTF::Ttopen::ref_cache($lookup->{'POST_CLASS'}, $ctables, 8),
- $num);
- $base_off = 12;
- }
-
- $out .= pack('n*', (0) x $num);
- $offc = length($out);
- for ($i = 0; $i < $num; $i++)
- {
- $r = $lookup->{'RULES'}[$i];
- next unless exists $r->[0]{'ACTION'};
- $numd = $#{$r} + 1;
- substr($out, ($i << 1) + $base_off, 2) = pack('n', $offc);
- $out .= pack('n*', $numd, (0) x $numd);
- $offd = length($out) - $offc;
- for ($j = 0; $j < $numd; $j++)
- {
- substr($out, $offc + 2 + ($j << 1), 2) = pack('n', $offd);
- if ($type == 4)
- {
- $out .= pack('n*', $r->[$j]{'ACTION'}[0], $#{$r->[$j]{'MATCH'}} + 2,
- @{$r->[$j]{'MATCH'}});
- } elsif ($type == 5)
- {
- $out .= pack('n*', $#{$r->[$j]{'MATCH'}} + 2,
- $#{$r->[$j]{'ACTION'}} + 1,
- @{$r->[$j]{'MATCH'}});
- foreach $t (@{$r->[$j]{'ACTION'}})
- { $out .= pack('n2', @$t); }
- } elsif ($type == 6)
- {
- $out .= pack('n*', $#{$r->[$j]{'PRE'}} + 1, @{$r->[$j]{'PRE'}},
- $#{$r->[$j]{'MATCH'}} + 2, @{$r->[$j]{'MATCH'}},
- $#{$r->[$j]{'POST'}} + 1, @{$r->[$j]{'POST'}},
- $#{$r->[$j]{'ACTION'}} + 1);
- foreach $t (@{$r->[$j]{'ACTION'}})
- { $out .= pack('n2', @$t); }
- }
- $offd = length($out) - $offc;
- }
- $offc = length($out);
- }
- } elsif ($type == 5 && $fmt == 3)
- {
- $out .= pack('n3', $fmt, $#{$lookup->{'RULES'}[0][0]{'MATCH'}} + 1,
- $#{$lookup->{'RULES'}[0][0]{'ACTION'}} + 1);
- foreach $t (@{$lookup->{'RULES'}[0][0]{'MATCH'}})
- { $out .= pack('n', Font::TTF::Ttopen::ref_cache($t, $ctables, length($out))); }
- foreach $t (@{$lookup->{'RULES'}[0][0]{'ACTION'}})
- { $out .= pack('n2', @$t); }
- } elsif ($type == 6 && $fmt == 3)
- {
- $r = $lookup->{'RULES'}[0][0];
- $out .= pack('n2', $fmt, $#{$r->{'PRE'}} + 1);
- foreach $t (@{$r->{'PRE'}})
- { $out .= Font::TTF::Ttopen::ref_cache($t, $ctables, length($out)); }
- $out .= pack('n', $#{$r->{'MATCH'}} + 1);
- foreach $t (@{$r->{'MATCH'}})
- { $out .= Font::TTF::Ttopen::ref_cache($t, $ctables, length($out)); }
- $out .= pack('n', $#{$r->{'POST'}} + 1);
- foreach $t (@{$r->{'POST'}})
- { $out .= Font::TTF::Ttopen::ref_cache($t, $ctables, length($out)); }
- $out .= pack('n', $#{$r->{'ACTION'}} + 1);
- foreach $t (@{$r->{'ACTION'}})
- { $out .= pack('n2', @$t); }
- }
- $out;
-}
-
-=head1 BUGS
-
-=over 4
-
-=item *
-
-No way to share cachable items (coverage tables, classes, anchors, device tables)
-across different lookups. The items are always output after the lookup and
-repeated if necessary. Within lookup sharing is possible.
-
-=back
-
-=head1 AUTHOR
-
-Martin Hosken Martin_Hosken at sil.org. See L<Font::TTF::Font> for copyright and
-licensing.
-
-=cut
-
-1;
-
+package Font::TTF::Ttopen;
+
+=head1 NAME
+
+Font::TTF::Ttopen - Opentype superclass for standard Opentype lookup based tables
+(GSUB and GPOS)
+
+=head1 DESCRIPTION
+
+Handles all the script, lang, feature, lookup stuff for a
+L<Font::TTF::Gsub>/L<Font::TTF::Gpos> table leaving the class specifics to the
+subclass
+
+=head1 INSTANCE VARIABLES
+
+The instance variables of an opentype table form a complex sub-module hierarchy.
+
+=over 4
+
+=item Version
+
+This contains the version of the table as a floating point number
+
+=item SCRIPTS
+
+The scripts list is a hash of script tags. Each script tag (of the form
+$t->{'SCRIPTS'}{$tag}) has information below it.
+
+=over 8
+
+=item OFFSET
+
+This variable is preceeded by a space and gives the offset from the start of the
+table (not the table section) to the script table for this script
+
+=item REFTAG
+
+This variable is preceded by a space and gives a corresponding script tag to this
+one such that the offsets in the file are the same. When writing, it is up to the
+caller to ensure that the REFTAGs are set correctly, since these will be used to
+assume that the scripts are identical. Note that REFTAG must refer to a script which
+has no REFTAG of its own.
+
+=item DEFAULT
+
+This corresponds to the default language for this script, if there is one, and
+contains the same information as an itemised language
+
+=item LANG_TAGS
+
+This contains an array of language tag strings (each 4 bytes) corresponding to
+the languages listed by this script
+
+=item $lang
+
+Each language is a hash containing its information:
+
+=over 12
+
+=item OFFSET
+
+This variable is preceeded by a a space and gives the offset from the start of
+the whole table to the language table for this language
+
+=item REFTAG
+
+This variable is preceded by a space and has the same function as for the script
+REFTAG, only for the languages within a script.
+
+=item RE-ORDER
+
+This indicates re-ordering information, and has not been set. The value should
+always be 0.
+
+=item DEFAULT
+
+This holds the index of the default feature, if there is one, or -1 otherwise.
+
+=item FEATURES
+
+This is an array of feature indices which index into the FEATURES instance
+variable of the table
+
+=back
+
+=back
+
+=item FEATURES
+
+The features section of instance variables corresponds to the feature table in
+the opentype table.
+
+=over 8
+
+=item FEAT_TAGS
+
+This array gives the ordered list of feature tags for this table. It is used during
+reading and writing for converting between feature index and feature tag.
+
+=back
+
+The rest of the FEATURES variable is itself a hash based on the feature tag for
+each feature. Each feature has the following structure:
+
+=over 8
+
+=item OFFSET
+
+This attribute is preceeded by a space and gives the offset relative to the start of the whole
+table of this particular feature.
+
+=item PARMS
+
+This is an unused offset to the parameters for each feature
+
+=item LOOKUPS
+
+This is an array containing indices to lookups in the LOOKUP instance variable of the table
+
+=item INDEX
+
+This gives the feature index for this feature and is used during reading and writing for
+converting between feature tag and feature index.
+
+=back
+
+=item LOOKUP
+
+This variable is an array of lookups in order and is indexed via the features of a language of a
+script. Each lookup contains subtables and other information:
+
+=over 8
+
+=item OFFSET
+
+This name is preceeded by a space and contains the offset from the start of the table to this
+particular lookup
+
+=item TYPE
+
+This is a subclass specific type for a lookup. It stipulates the type of lookup and hence subtables
+within the lookup
+
+=item FLAG
+
+Holds the lookup flag bits
+
+=item SUB
+
+This holds an array of subtables which are subclass specific. Each subtable must have
+an OFFSET. The other variables described here are an abstraction used in both the
+GSUB and GPOS tables which are the target subclasses of this class.
+
+=over 12
+
+=item OFFSET
+
+This is preceeded by a space and gives the offset relative to the start of the table for this
+subtable
+
+=item FORMAT
+
+Gives the sub-table sub format for this GSUB subtable. It is assumed that this
+value is correct when it comes time to write the subtable.
+
+=item COVERAGE
+
+Most lookups consist of a coverage table corresponding to the first
+glyph to match. The offset of this coverage table is stored here and the coverage
+table looked up against the GSUB table proper. There are two lookups
+without this initial coverage table which is used to index into the RULES array.
+These lookups have one element in the RULES array which is used for the whole
+match.
+
+=item RULES
+
+The rules are a complex array. Each element of the array corresponds to an
+element in the coverage table (governed by the coverage index). If there is
+no coverage table, then there is considered to be only one element in the rules
+array. Each element of the array is itself an array corresponding to the
+possibly multiple string matches which may follow the initial glyph. Each
+element of this array is a hash with fixed keys corresponding to information
+needed to match a glyph string or act upon it. Thus the RULES element is an
+array of arrays of hashes which contain the following keys:
+
+=over 16
+
+=item MATCH
+
+This contains a sequence of elements held as an array. The elements may be
+glyph ids (gid), class ids (cids), or offsets to coverage tables. Each element
+corresponds to one glyph in the glyph string. See MATCH_TYPE for details of
+how the different element types are marked.
+
+=item PRE
+
+This array holds the sequence of elements preceeding the first match element
+and has the same form as the MATCH array.
+
+=item POST
+
+This array holds the sequence of elements to be tested for following the match
+string and is of the same form as the MATCH array.
+
+=item ACTION
+
+This array holds information regarding what should be done if a match is found.
+The array may either hold glyph ids (which are used to replace or insert or
+whatever glyphs in the glyph string) or 2 element arrays consisting of:
+
+=over 20
+
+=item OFFSET
+
+Offset from the start of the matched string that the lookup should start at
+when processing the substring.
+
+=item LOOKUP_INDEX
+
+The index to a lookup to be acted upon on the match string.
+
+=back
+
+=back
+
+=back
+
+=back
+
+=item CLASS
+
+For those lookups which use class categories rather than glyph ids for matching
+this is the offset to the class definition used to categories glyphs in the
+match string.
+
+=item PRE_CLASS
+
+This is the offset to the class definition for the before match glyphs
+
+=item POST_CLASS
+
+This is the offset to the class definition for the after match glyphs.
+
+=item ACTION_TYPE
+
+This string holds the type of information held in the ACTION variable of a RULE.
+It is subclass specific.
+
+=item MATCH_TYPE
+
+This holds the type of information in the MATCH array of a RULE. This is subclass
+specific.
+
+=item ADJUST
+
+This corresponds to a single action for all items in a coverage table. The meaning
+is subclass specific.
+
+=item CACHE
+
+This key starts with a space
+
+A hash of other tables (such as coverage tables, classes, anchors, device tables)
+based on the offset given in the subtable to that other information.
+Note that the documentation is particularly
+unhelpful here in that such tables are given as offsets relative to the
+beginning of the subtable not the whole GSUB table. This includes those items which
+are stored relative to another base within the subtable.
+
+=back
+
+
+=head1 METHODS
+
+=cut
+
+use Font::TTF::Table;
+use Font::TTF::Utils;
+use Font::TTF::Coverage;
+use strict;
+use vars qw(@ISA);
+
+ at ISA = qw(Font::TTF::Table);
+
+=head2 $t->read
+
+Reads the table passing control to the subclass to handle the subtable specifics
+
+=cut
+
+sub read
+{
+ my ($self) = @_;
+ my ($dat, $i, $l, $oScript, $oFeat, $oLook, $tag, $nScript, $off, $dLang, $nLang, $lTag);
+ my ($nFeat, $nLook, $nSub, $j, $temp);
+ my ($fh) = $self->{' INFILE'};
+ my ($moff) = $self->{' OFFSET'};
+
+ $self->SUPER::read or return $self;
+ $fh->read($dat, 10);
+ ($self->{'Version'}, $oScript, $oFeat, $oLook) = TTF_Unpack("fSSS", $dat);
+
+# read features first so that in the script/lang hierarchy we can use feature tags
+
+ $fh->seek($moff + $oFeat, 0);
+ $fh->read($dat, 2);
+ $nFeat = unpack("n", $dat);
+ $self->{'FEATURES'} = {};
+ $l = $self->{'FEATURES'};
+ $fh->read($dat, 6 * $nFeat);
+ for ($i = 0; $i < $nFeat; $i++)
+ {
+ ($tag, $off) = unpack("a4n", substr($dat, $i * 6, 6));
+ while (defined $l->{$tag})
+ {
+ if ($tag =~ m/(.*?)\s_(\d+)$/o)
+ { $tag = $1 . " _" . ($2 + 1); }
+ else
+ { $tag .= " _0"; }
+ }
+ $l->{$tag}{' OFFSET'} = $off + $oFeat;
+ $l->{$tag}{'INDEX'} = $i;
+ push (@{$l->{'FEAT_TAGS'}}, $tag);
+ }
+
+ foreach $tag (grep {length($_) == 4} keys %$l)
+ {
+ $fh->seek($moff + $l->{$tag}{' OFFSET'}, 0);
+ $fh->read($dat, 4);
+ ($l->{$tag}{'PARMS'}, $nLook) = unpack("n2", $dat);
+ $fh->read($dat, $nLook * 2);
+ $l->{$tag}{'LOOKUPS'} = [unpack("n*", $dat)];
+ }
+
+# Now the script/lang hierarchy
+
+ $fh->seek($moff + $oScript, 0);
+ $fh->read($dat, 2);
+ $nScript = unpack("n", $dat);
+ $self->{'SCRIPTS'} = {};
+ $l = $self->{'SCRIPTS'};
+ $fh->read($dat, 6 * $nScript);
+ for ($i = 0; $i < $nScript; $i++)
+ {
+ ($tag, $off) = unpack("a4n", substr($dat, $i * 6, 6));
+ $off += $oScript;
+ foreach (keys %$l)
+ { $l->{$tag}{' REFTAG'} = $_ if ($l->{$_}{' OFFSET'} == $off
+ && !defined $l->{$_}{' REFTAG'}); }
+ $l->{$tag}{' OFFSET'} = $off;
+ }
+
+ foreach $tag (keys %$l)
+ {
+ next if ($l->{$tag}{' REFTAG'});
+ $fh->seek($moff + $l->{$tag}{' OFFSET'}, 0);
+ $fh->read($dat, 4);
+ ($dLang, $nLang) = unpack("n2", $dat);
+ $l->{$tag}{'DEFAULT'}{' OFFSET'} =
+ $dLang + $l->{$tag}{' OFFSET'} if $dLang;
+ $fh->read($dat, 6 * $nLang);
+ for ($i = 0; $i < $nLang; $i++)
+ {
+ ($lTag, $off) = unpack("a4n", substr($dat, $i * 6, 6));
+ $off += $l->{$tag}{' OFFSET'};
+ $l->{$tag}{$lTag}{' OFFSET'} = $off;
+ foreach (@{$l->{$tag}{'LANG_TAGS'}})
+ { $l->{$tag}{$lTag}{' REFTAG'} = $_ if ($l->{$tag}{$_}{' OFFSET'} == $off
+ && !$l->{$tag}{$_}{' REFTAG'}); }
+ push (@{$l->{$tag}{'LANG_TAGS'}}, $lTag);
+ }
+ foreach $lTag (@{$l->{$tag}{'LANG_TAGS'}}, 'DEFAULT')
+ {
+ next unless defined $l->{$tag}{$lTag};
+ next if ($l->{$tag}{$lTag}{' REFTAG'});
+ $fh->seek($moff + $l->{$tag}{$lTag}{' OFFSET'}, 0);
+ $fh->read($dat, 6);
+ ($l->{$tag}{$lTag}{'RE-ORDER'}, $l->{$tag}{$lTag}{'DEFAULT'}, $nFeat)
+ = unpack("n3", $dat);
+ $fh->read($dat, $nFeat * 2);
+ $l->{$tag}{$lTag}{'FEATURES'} = [map {$self->{'FEATURES'}{'FEAT_TAGS'}[$_]} unpack("n*", $dat)];
+ }
+ foreach $lTag (@{$l->{$tag}{'LANG_TAGS'}}, 'DEFAULT')
+ {
+ next unless $l->{$tag}{$lTag}{' REFTAG'};
+ $temp = $l->{$tag}{$lTag}{' REFTAG'};
+ $l->{$tag}{$lTag} = ©($l->{$tag}{$temp});
+ $l->{$tag}{$lTag}{' REFTAG'} = $temp;
+ }
+ }
+ foreach $tag (keys %$l)
+ {
+ next unless $l->{$tag}{' REFTAG'};
+ $temp = $l->{$tag}{' REFTAG'};
+ $l->{$tag} = ©($l->{$temp});
+ $l->{$tag}{' REFTAG'} = $temp;
+ }
+
+# And finally the lookups
+
+ $fh->seek($moff + $oLook, 0);
+ $fh->read($dat, 2);
+ $nLook = unpack("n", $dat);
+ $fh->read($dat, $nLook * 2);
+ $i = 0;
+ map { $self->{'LOOKUP'}[$i++]{' OFFSET'} = $_; } unpack("n*", $dat);
+
+ for ($i = 0; $i < $nLook; $i++)
+ {
+ $l = $self->{'LOOKUP'}[$i];
+ $fh->seek($l->{' OFFSET'} + $moff + $oLook, 0);
+ $fh->read($dat, 6);
+ ($l->{'TYPE'}, $l->{'FLAG'}, $nSub) = unpack("n3", $dat);
+ $fh->read($dat, $nSub * 2);
+ $j = 0;
+ map { $l->{'SUB'}[$j]{' OFFSET'} = $_; } unpack("n*", $dat);
+ for ($j = 0; $j < $nSub; $j++)
+ {
+ $fh->seek($moff + $oLook + $l->{' OFFSET'} + $l->{'SUB'}[$j]{' OFFSET'}, 0);
+ $self->read_sub($fh, $l, $j);
+ }
+ }
+ return $self;
+}
+
+=head2 $t->read_sub($fh, $lookup, $index)
+
+This stub is to allow subclasses to read subtables of lookups in a table specific manner. A
+reference to the lookup is passed in along with the subtable index. The file is located at the
+start of the subtable to be read
+
+=cut
+
+sub read_sub
+{ }
+
+
+=head2 $t->extension()
+
+Returns the lookup number for the extension table that allows access to 32-bit offsets.
+
+=cut
+
+sub extension
+{ }
+
+
+=head2 $t->out($fh)
+
+Writes this Opentype table to the output calling $t->out_sub for each sub table
+at the appropriate point in the output. The assumption is that on entry the
+number of scripts, languages, features, lookups, etc. are all resolved and
+the relationships fixed. This includes a script's LANG_TAGS list and that all
+scripts and languages in their respective dictionaries either have a REFTAG or contain
+real data.
+
+=cut
+
+sub out
+{
+ my ($self, $fh) = @_;
+ my ($i, $j, $base, $off, $tag, $t, $l, $lTag, $oScript, @script, @tags);
+ my ($end, $nTags, @offs, $oFeat, $oLook, $nSub, $nSubs, $big);
+
+ return $self->SUPER::out($fh) unless $self->{' read'};
+
+# First sort the features
+ $i = 0;
+ $self->{'FEATURES'}{'FEAT_TAGS'} = [sort grep {length($_) == 4 || m/\s_\d+$/o} %{$self->{'FEATURES'}}]
+ if (!defined $self->{'FEATURES'}{'FEAT_TAGS'});
+ foreach $t (@{$self->{'FEATURES'}{'FEAT_TAGS'}})
+ { $self->{'FEATURES'}{$t}{'INDEX'} = $i++; }
+
+ $base = $fh->tell();
+ $fh->print(TTF_Pack("f", $self->{'Version'}));
+ $fh->print(pack("n3", 10, 0, 0));
+ $oScript = $fh->tell() - $base;
+ @script = sort grep {length($_) == 4} keys %{$self->{'SCRIPTS'}};
+ $fh->print(pack("n", $#script + 1));
+ foreach $t (@script)
+ { $fh->print(pack("a4n", $t, 0)); }
+
+ $end = $fh->tell();
+ foreach $t (@script)
+ {
+ $fh->seek($end, 0);
+ $tag = $self->{'SCRIPTS'}{$t};
+ next if ($tag->{' REFTAG'});
+ $tag->{' OFFSET'} = tell($fh) - $base - $oScript;
+ $fh->print(pack("n2", 0, $#{$tag->{'LANG_TAGS'}} + 1));
+ foreach $lTag (sort @{$tag->{'LANG_TAGS'}})
+ { $fh->print(pack("a4n", $lTag, 0)); }
+ foreach $lTag (@{$tag->{'LANG_TAGS'}}, 'DEFAULT')
+ {
+ my ($def);
+ $l = $tag->{$lTag};
+ next if (!defined $l || $l->{' REFTAG'} ne '');
+ $l->{' OFFSET'} = tell($fh) - $base - $oScript - $tag->{' OFFSET'};
+ if (defined $l->{'DEFAULT'})
+# { $def = $self->{'FEATURES'}{$l->{'FEATURES'}[$l->{'DEFAULT'}]}{'INDEX'}; }
+ { $def = $l->{'DEFAULT'}; }
+ else
+ { $def = -1; }
+ $fh->print(pack("n*", $l->{'RE_ORDER'}, $def, $#{$l->{'FEATURES'}} + 1,
+ map {$self->{'FEATURES'}{$_}{'INDEX'}} @{$l->{'FEATURES'}}));
+ }
+ $end = $fh->tell();
+ if ($tag->{'DEFAULT'}{' REFTAG'} || defined $tag->{'DEFAULT'}{'FEATURES'})
+ {
+ $fh->seek($base + $oScript + $tag->{' OFFSET'}, 0);
+ $off = $tag->{'DEFAULT'}{' REFTAG'} ?
+ $tag->{$tag->{'DEFAULT'}{' REFTAG'}}{' OFFSET'} :
+ $tag->{'DEFAULT'}{' OFFSET'};
+ $fh->print(pack("n", $off));
+ }
+ $fh->seek($base + $oScript + $tag->{' OFFSET'} + 4, 0);
+ foreach (sort @{$tag->{'LANG_TAGS'}})
+ {
+ $off = $tag->{$_}{' REFTAG'} ? $tag->{$tag->{$_}{' REFTAG'}}{' OFFSET'} :
+ $tag->{$_}{' OFFSET'};
+ $fh->print(pack("a4n", $_, $off));
+ }
+ }
+ $fh->seek($base + $oScript + 2, 0);
+ foreach $t (@script)
+ {
+ $tag = $self->{'SCRIPTS'}{$t};
+ $off = $tag->{' REFTAG'} ? $tag->{$tag->{' REFTAG'}}{' OFFSET'} : $tag->{' OFFSET'};
+ $fh->print(pack("a4n", $t, $off));
+ }
+
+ $fh->seek($end, 0);
+ $oFeat = $end - $base;
+ $nTags = $#{$self->{'FEATURES'}{'FEAT_TAGS'}} + 1;
+ $fh->print(pack("n", $nTags));
+ $fh->print(pack("a4n", " ", 0) x $nTags);
+
+ foreach $t (@{$self->{'FEATURES'}{'FEAT_TAGS'}})
+ {
+ $tag = $self->{'FEATURES'}{$t};
+ $tag->{' OFFSET'} = tell($fh) - $base - $oFeat;
+ $fh->print(pack("n*", 0, $#{$tag->{'LOOKUPS'}} + 1, @{$tag->{'LOOKUPS'}}));
+ }
+ $end = $fh->tell();
+ $fh->seek($oFeat + $base + 2, 0);
+ foreach $t (@{$self->{'FEATURES'}{'FEAT_TAGS'}})
+ { $fh->print(pack("a4n", $t, $self->{'FEATURES'}{$t}{' OFFSET'})); }
+
+ undef $big;
+ $fh->seek($end, 0);
+ $oLook = $end - $base;
+
+ # Start Lookup List Table
+ $nTags = $#{$self->{'LOOKUP'}} + 1;
+ $fh->print(pack("n", $nTags));
+ $fh->print(pack("n", 0) x $nTags);
+ $end = $fh->tell(); # end of LookupListTable = start of Lookups
+ foreach $tag (@{$self->{'LOOKUP'}})
+ { $nSubs += $self->num_sub($tag); }
+ for ($i = 0; $i < $nTags; $i++)
+ {
+ $fh->seek($end, 0);
+ $tag = $self->{'LOOKUP'}[$i];
+ $off = $end - $base - $oLook; # BH 2004-03-04
+ # Is there room, from the start of this i'th lookup, for this and the remaining
+ # lookups to be wrapped in extension lookups?
+ if (!defined $big && $off + ($nTags - $i) * 6 + $nSubs * 10 > 65535) # BH 2004-03-04
+ {
+ # Not enough room -- need to start an extension!
+ my ($k, $ext);
+ $ext = $self->extension();
+ # Must turn previous lookup into the first extension
+ $i--;
+ $tag = $self->{'LOOKUP'}[$i];
+ $end = $tag->{' OFFSET'} + $base + $oLook;
+ $fh->seek($end, 0);
+ $big = $i;
+ # For this and the remaining lookups, build extensions lookups
+ for ($j = $i; $j < $nTags; $j++)
+ {
+ $tag = $self->{'LOOKUP'}[$j];
+ $nSub = $self->num_sub($tag);
+ $fh->print(pack("nnn", $ext, $tag->{'FLAG'}, $nSub));
+ $fh->print(pack("n*", map {$_ * 8 + 6 + $nSub * 2} (0 .. $nSub-1))); # BH 2004-03-04
+ $tag->{' EXT_OFFSET'} = $fh->tell(); # = first extension lookup subtable
+ $tag->{' OFFSET'} = $tag->{' EXT_OFFSET'} - $nSub * 2 - 6 - $base - $oLook; # offset to this extension lookup
+ for ($k = 0; $k < $nSub; $k++)
+ { $fh->print(pack('nnN', 1, $tag->{'TYPE'}, 0)); }
+ }
+
+ $tag = $self->{'LOOKUP'}[$i];
+ # Leave file positioned after all the extension lookups -- where the referenced lookups will start.
+ }
+ $tag->{' OFFSET'} = $off unless defined $big; # BH 2004-03-04
+ $nSub = $self->num_sub($tag);
+ if (!defined $big)
+ {
+ $fh->print(pack("nnn", $tag->{'TYPE'}, $tag->{'FLAG'}, $nSub));
+ $fh->print(pack("n", 0) x $nSub);
+ }
+ else
+ { $end = $tag->{' EXT_OFFSET'}; }
+ @offs = ();
+ for ($j = 0; $j < $nSub; $j++)
+ {
+ push(@offs, tell($fh) - $end);
+ $self->out_sub($fh, $tag, $j);
+ }
+ $end = $fh->tell();
+ if (!defined $big)
+ {
+ $fh->seek($tag->{' OFFSET'} + $base + $oLook + 6, 0);
+ $fh->print(pack("n*", @offs));
+ }
+ else
+ {
+ $fh->seek($tag->{' EXT_OFFSET'}, 0);
+ for ($j = 0; $j < $nSub; $j++)
+ { $fh->print(pack('nnN', 1, $tag->{'TYPE'}, $offs[$j] - $j * 8)); }
+ }
+ }
+ $fh->seek($oLook + $base + 2, 0);
+ $fh->print(pack("n*", map {$self->{'LOOKUP'}[$_]{' OFFSET'}} (0 .. $nTags - 1)));
+ $fh->seek($base + 6, 0);
+ $fh->print(pack('n2', $oFeat, $oLook));
+ $fh->seek($end, 0);
+ $self;
+}
+
+
+=head2 $t->num_sub($lookup)
+
+Asks the subclass to count the number of subtables for a particular lookup and to
+return that value. Used in out().
+
+=cut
+
+sub num_sub
+{
+ my ($self, $lookup) = @_;
+
+ return $#{$lookup->{'SUB'}} + 1;
+}
+
+
+=head2 $t->out_sub($fh, $lookup, $index)
+
+This stub is to allow subclasses to output subtables of lookups in a table specific manner. A
+reference to the lookup is passed in along with the subtable index. The file is located at the
+start of the subtable to be output
+
+=cut
+
+sub out_sub
+{ }
+
+
+=head1 Internal Functions & Methods
+
+Most of these methods are used by subclasses for handling such things as coverage
+tables.
+
+=head2 copy($ref)
+
+Internal function to copy the top level of a dictionary to create a new dictionary.
+Only the top level is copied.
+
+=cut
+
+sub copy
+{
+ my ($ref) = @_;
+ my ($res) = {};
+
+ foreach (keys %$ref)
+ { $res->{$_} = $ref->{$_}; }
+ $res;
+}
+
+
+=head2 $t->read_cover($cover_offset, $lookup_loc, $lookup, $fh, $is_cover)
+
+Reads a coverage table and stores the results in $lookup->{' CACHE'}, that is, if
+it hasn't been read already.
+
+=cut
+
+sub read_cover
+{
+ my ($self, $offset, $base, $lookup, $fh, $is_cover) = @_;
+ my ($loc) = $fh->tell();
+ my ($cover, $str);
+
+ return undef unless $offset;
+ $str = sprintf("%X", $base + $offset);
+ return $lookup->{' CACHE'}{$str} if defined $lookup->{' CACHE'}{$str};
+ $fh->seek($base + $offset, 0);
+ $cover = Font::TTF::Coverage->new($is_cover)->read($fh);
+ $fh->seek($loc, 0);
+ $lookup->{' CACHE'}{$str} = $cover;
+ return $cover;
+}
+
+
+=head2 ref_cache($obj, $cache, $offset)
+
+Internal function to keep track of the local positioning of subobjects such as
+coverage and class definition tables, and their offsets.
+What happens is that the cache is a hash of
+sub objects indexed by the reference (using a string mashing of the
+reference name which is valid for the duration of the reference) and holds a
+list of locations in the output string which should be filled in with the
+offset to the sub object when the final string is output in out_final.
+
+Uses tricks for Tie::Refhash
+
+=cut
+
+sub ref_cache
+{
+ my ($obj, $cache, $offset) = @_;
+
+ return 0 unless defined $obj;
+ $cache->{"$obj"}[0] = $obj unless defined $cache->{"$obj"};
+ push (@{$cache->{"$obj"}[1]}, $offset);
+ return 0;
+}
+
+
+=head2 out_final($fh, $out, $cache_list, $state)
+
+Internal function to actually output everything to the file handle given that
+now we know the offset to the first sub object to be output and which sub objects
+are to be output and what locations need to be updated, we can now
+generate everything. $cache_list is an array of two element arrays. The first element
+is a cache object, the second is an offset to be subtracted from each reference
+to that object made in the cache.
+
+If $state is 1, then the output is not sent to the filehandle and the return value
+is the string to be output. If $state is absent or 0 then output is not limited
+by storing in a string first and the return value is "";
+
+=cut
+
+sub out_final
+{
+ my ($fh, $out, $cache_list, $state) = @_;
+ my ($len) = length($out);
+ my ($base_loc) = $state ? 0 : $fh->tell();
+ my ($loc, $t, $r, $s, $master_cache, $offs, $str);
+
+ $fh->print($out) unless $state; # first output the current attempt
+ foreach $r (@$cache_list)
+ {
+ $offs = $r->[1];
+ foreach $t (sort keys %{$r->[0]})
+ {
+ $str = "$t";
+ if (!defined $master_cache->{$str})
+ {
+ $master_cache->{$str} = ($state ? length($out) : $fh->tell())
+ - $base_loc;
+ if ($state)
+ { $out .= $r->[0]{$str}[0]->out($fh, 1); }
+ else
+ { $r->[0]{$str}[0]->out($fh, 0); }
+ }
+ foreach $s (@{$r->[0]{$str}[1]})
+ { substr($out, $s, 2) = pack('n', $master_cache->{$str} - $offs); }
+ }
+ }
+ if ($state)
+ { return $out; }
+ else
+ {
+ $loc = $fh->tell();
+ $fh->seek($base_loc, 0);
+ $fh->print($out); # the corrected version
+ $fh->seek($loc, 0);
+ }
+}
+
+
+=head2 $self->read_context($lookup, $fh, $type, $fmt, $cover, $count, $loc)
+
+Internal method to read context (simple and chaining context) lookup subtables for
+the GSUB and GPOS table types. The assumed values for $type correspond to those
+for GSUB, so GPOS should adjust the values upon calling.
+
+=cut
+
+sub read_context
+{
+ my ($self, $lookup, $fh, $type, $fmt, $cover, $count, $loc) = @_;
+ my ($dat, $i, $s, $t, @subst, @srec, $mcount, $scount);
+
+ if ($type == 5 && $fmt < 3)
+ {
+ if ($fmt == 2)
+ {
+ $fh->read($dat, 2);
+ $lookup->{'CLASS'} = $self->read_cover($count, $loc, $lookup, $fh, 0);
+ $count = TTF_Unpack('S', $dat);
+ }
+ $fh->read($dat, $count << 1);
+ foreach $s (TTF_Unpack('S*', $dat))
+ {
+ if ($s == 0)
+ {
+ push (@{$lookup->{'RULES'}}, []);
+ next;
+ }
+ @subst = ();
+ $fh->seek($loc + $s, 0);
+ $fh->read($dat, 2);
+ $t = TTF_Unpack('S', $dat);
+ $fh->read($dat, $t << 1);
+ foreach $t (TTF_Unpack('S*', $dat))
+ {
+ $fh->seek($loc + $s + $t, 0);
+ @srec = ();
+ $fh->read($dat, 4);
+ ($mcount, $scount) = TTF_Unpack('S2', $dat);
+ $mcount--;
+ $fh->read($dat, ($mcount << 1) + ($scount << 2));
+ for ($i = 0; $i < $scount; $i++)
+ { push (@srec, [TTF_Unpack('S2', substr($dat,
+ ($mcount << 1) + ($i << 2), 4))]); }
+ push (@subst, {'ACTION' => [@srec],
+ 'MATCH' => [TTF_Unpack('S*',
+ substr($dat, 0, $mcount << 1))]});
+ }
+ push (@{$lookup->{'RULES'}}, [@subst]);
+ }
+ $lookup->{'ACTION_TYPE'} = 'l';
+ $lookup->{'MATCH_TYPE'} = ($fmt == 2 ? 'c' : 'g');
+ } elsif ($type == 5 && $fmt == 3)
+ {
+ $fh->read($dat, ($cover << 1) + ($count << 2));
+ @subst = (); @srec = ();
+ for ($i = 0; $i < $cover; $i++)
+ { push (@subst, $self->read_cover(TTF_Unpack('S', substr($dat, $i << 1, 2)),
+ $loc, $lookup, $fh, 1)); }
+ for ($i = 0; $i < $count; $i++)
+ { push (@srec, [TTF_Unpack('S2', substr($dat, ($count << 1) + ($i << 2), 4))]); }
+ $lookup->{'RULES'} = [[{'ACTION' => [@srec], 'MATCH' => [@subst]}]];
+ $lookup->{'ACTION_TYPE'} = 'l';
+ $lookup->{'MATCH_TYPE'} = 'o';
+ } elsif ($type == 6 && $fmt < 3)
+ {
+ if ($fmt == 2)
+ {
+ $fh->read($dat, 6);
+ $lookup->{'PRE_CLASS'} = $self->read_cover($count, $loc, $lookup, $fh, 0) if $count;
+ ($i, $mcount, $count) = TTF_Unpack('S3', $dat); # messy: 2 classes & count
+ $lookup->{'CLASS'} = $self->read_cover($i, $loc, $lookup, $fh, 0) if $i;
+ $lookup->{'POST_CLASS'} = $self->read_cover($mcount, $loc, $lookup, $fh, 0) if $mcount;
+ }
+ $fh->read($dat, $count << 1);
+ foreach $s (TTF_Unpack('S*', $dat))
+ {
+ if ($s == 0)
+ {
+ push (@{$lookup->{'RULES'}}, []);
+ next;
+ }
+ @subst = ();
+ $fh->seek($loc + $s, 0);
+ $fh->read($dat, 2);
+ $t = TTF_Unpack('S', $dat);
+ $fh->read($dat, $t << 1);
+ foreach $i (TTF_Unpack('S*', $dat))
+ {
+ $fh->seek($loc + $s + $i, 0);
+ @srec = ();
+ $t = {};
+ $fh->read($dat, 2);
+ $mcount = TTF_Unpack('S', $dat);
+ if ($mcount > 0)
+ {
+ $fh->read($dat, $mcount << 1);
+ $t->{'PRE'} = [TTF_Unpack('S*', $dat)];
+ }
+ $fh->read($dat, 2);
+ $mcount = TTF_Unpack('S', $dat);
+ if ($mcount > 1)
+ {
+ $fh->read($dat, ($mcount - 1) << 1);
+ $t->{'MATCH'} = [TTF_Unpack('S*', $dat)];
+ }
+ $fh->read($dat, 2);
+ $mcount = TTF_Unpack('S', $dat);
+ if ($mcount > 0)
+ {
+ $fh->read($dat, $mcount << 1);
+ $t->{'POST'} = [TTF_Unpack('S*', $dat)];
+ }
+ $fh->read($dat, 2);
+ $scount = TTF_Unpack('S', $dat);
+ $fh->read($dat, $scount << 2);
+ for ($i = 0; $i < $scount; $i++)
+ { push (@srec, [TTF_Unpack('S2', substr($dat, $i << 2))]); }
+ $t->{'ACTION'} = [@srec];
+ push (@subst, $t);
+ }
+ push (@{$lookup->{'RULES'}}, [@subst]);
+ }
+ $lookup->{'ACTION_TYPE'} = 'l';
+ $lookup->{'MATCH_TYPE'} = ($fmt == 2 ? 'c' : 'g');
+ } elsif ($type == 6 && $fmt == 3)
+ {
+ $t = {};
+ unless ($cover == 0)
+ {
+ @subst = ();
+ $fh->read($dat, $cover << 1);
+ foreach $s (TTF_Unpack('S*', $dat))
+ { push(@subst, $self->read_cover($s, $loc, $lookup, $fh, 1)); }
+ $t->{'PRE'} = [@subst];
+ }
+ $fh->read($dat, 2);
+ $count = TTF_Unpack('S', $dat);
+ unless ($count == 0)
+ {
+ @subst = ();
+ $fh->read($dat, $count << 1);
+ foreach $s (TTF_Unpack('S*', $dat))
+ { push(@subst, $self->read_cover($s, $loc, $lookup, $fh, 1)); }
+ $t->{'MATCH'} = [@subst];
+ }
+ $fh->read($dat, 2);
+ $count = TTF_Unpack('S', $dat);
+ unless ($count == 0)
+ {
+ @subst = ();
+ $fh->read($dat, $count << 1);
+ foreach $s (TTF_Unpack('S*', $dat))
+ { push(@subst, $self->read_cover($s, $loc, $lookup, $fh, 1)); }
+ $t->{'POST'} = [@subst];
+ }
+ $fh->read($dat, 2);
+ $count = TTF_Unpack('S', $dat);
+ @subst = ();
+ $fh->read($dat, $count << 2);
+ for ($i = 0; $i < $count; $i++)
+ { push (@subst, [TTF_Unpack('S2', substr($dat, $i << 2, 4))]); }
+ $t->{'ACTION'} = [@subst];
+ $lookup->{'RULES'} = [[$t]];
+ $lookup->{'ACTION_TYPE'} = 'l';
+ $lookup->{'MATCH_TYPE'} = 'o';
+ }
+ $lookup;
+}
+
+
+=head2 $self->out_context($lookup, $fh, $type, $fmt, $ctables, $out, $num)
+
+Provides shared behaviour between GSUB and GPOS tables during output for context
+(chained and simple) rules. In addition, support is provided here for type 4 GSUB
+tables, which are not used in GPOS. The value for $type corresponds to the type
+in a GSUB table so calling from GPOS should adjust the value accordingly.
+
+=cut
+
+sub out_context
+{
+ my ($self, $lookup, $fh, $type, $fmt, $ctables, $out, $num) = @_;
+ my ($offc, $offd, $i, $j, $r, $t, $numd);
+
+ if (($type == 4 || $type == 5 || $type == 6) && ($fmt == 1 || $fmt == 2))
+ {
+ my ($base_off);
+
+ if ($fmt == 1)
+ {
+ $out = pack("nnn", $fmt, Font::TTF::Ttopen::ref_cache($lookup->{'COVERAGE'}, $ctables, 2),
+ $num);
+ $base_off = 6;
+ } elsif ($type == 5)
+ {
+ $out = pack("nnnn", $fmt, Font::TTF::Ttopen::ref_cache($lookup->{'COVERAGE'}, $ctables, 2),
+ Font::TTF::Ttopen::ref_cache($lookup->{'CLASS'}, $ctables, 4), $num);
+ $base_off = 8;
+ } elsif ($type == 6)
+ {
+ $out = pack("n6", $fmt, Font::TTF::Ttopen::ref_cache($lookup->{'COVERAGE'}, $ctables, 2),
+ Font::TTF::Ttopen::ref_cache($lookup->{'PRE_CLASS'}, $ctables, 4),
+ Font::TTF::Ttopen::ref_cache($lookup->{'CLASS'}, $ctables, 6),
+ Font::TTF::Ttopen::ref_cache($lookup->{'POST_CLASS'}, $ctables, 8),
+ $num);
+ $base_off = 12;
+ }
+
+ $out .= pack('n*', (0) x $num);
+ $offc = length($out);
+ for ($i = 0; $i < $num; $i++)
+ {
+ $r = $lookup->{'RULES'}[$i];
+ next unless exists $r->[0]{'ACTION'};
+ $numd = $#{$r} + 1;
+ substr($out, ($i << 1) + $base_off, 2) = pack('n', $offc);
+ $out .= pack('n*', $numd, (0) x $numd);
+ $offd = length($out) - $offc;
+ for ($j = 0; $j < $numd; $j++)
+ {
+ substr($out, $offc + 2 + ($j << 1), 2) = pack('n', $offd);
+ if ($type == 4)
+ {
+ $out .= pack('n*', $r->[$j]{'ACTION'}[0], $#{$r->[$j]{'MATCH'}} + 2,
+ @{$r->[$j]{'MATCH'}});
+ } elsif ($type == 5)
+ {
+ $out .= pack('n*', $#{$r->[$j]{'MATCH'}} + 2,
+ $#{$r->[$j]{'ACTION'}} + 1,
+ @{$r->[$j]{'MATCH'}});
+ foreach $t (@{$r->[$j]{'ACTION'}})
+ { $out .= pack('n2', @$t); }
+ } elsif ($type == 6)
+ {
+ $out .= pack('n*', $#{$r->[$j]{'PRE'}} + 1, @{$r->[$j]{'PRE'}},
+ $#{$r->[$j]{'MATCH'}} + 2, @{$r->[$j]{'MATCH'}},
+ $#{$r->[$j]{'POST'}} + 1, @{$r->[$j]{'POST'}},
+ $#{$r->[$j]{'ACTION'}} + 1);
+ foreach $t (@{$r->[$j]{'ACTION'}})
+ { $out .= pack('n2', @$t); }
+ }
+ $offd = length($out) - $offc;
+ }
+ $offc = length($out);
+ }
+ } elsif ($type == 5 && $fmt == 3)
+ {
+ $out .= pack('n3', $fmt, $#{$lookup->{'RULES'}[0][0]{'MATCH'}} + 1,
+ $#{$lookup->{'RULES'}[0][0]{'ACTION'}} + 1);
+ foreach $t (@{$lookup->{'RULES'}[0][0]{'MATCH'}})
+ { $out .= pack('n', Font::TTF::Ttopen::ref_cache($t, $ctables, length($out))); }
+ foreach $t (@{$lookup->{'RULES'}[0][0]{'ACTION'}})
+ { $out .= pack('n2', @$t); }
+ } elsif ($type == 6 && $fmt == 3)
+ {
+ $r = $lookup->{'RULES'}[0][0];
+ $out .= pack('n2', $fmt, $#{$r->{'PRE'}} + 1);
+ foreach $t (@{$r->{'PRE'}})
+ { $out .= Font::TTF::Ttopen::ref_cache($t, $ctables, length($out)); }
+ $out .= pack('n', $#{$r->{'MATCH'}} + 1);
+ foreach $t (@{$r->{'MATCH'}})
+ { $out .= Font::TTF::Ttopen::ref_cache($t, $ctables, length($out)); }
+ $out .= pack('n', $#{$r->{'POST'}} + 1);
+ foreach $t (@{$r->{'POST'}})
+ { $out .= Font::TTF::Ttopen::ref_cache($t, $ctables, length($out)); }
+ $out .= pack('n', $#{$r->{'ACTION'}} + 1);
+ foreach $t (@{$r->{'ACTION'}})
+ { $out .= pack('n2', @$t); }
+ }
+ $out;
+}
+
+=head1 BUGS
+
+=over 4
+
+=item *
+
+No way to share cachable items (coverage tables, classes, anchors, device tables)
+across different lookups. The items are always output after the lookup and
+repeated if necessary. Within lookup sharing is possible.
+
+=back
+
+=head1 AUTHOR
+
+Martin Hosken Martin_Hosken at sil.org. See L<Font::TTF::Font> for copyright and
+licensing.
+
+=cut
+
+1;
+
Modified: packages/libfont-ttf-perl/trunk/lib/Font/TTF/Useall.pm
===================================================================
--- packages/libfont-ttf-perl/trunk/lib/Font/TTF/Useall.pm 2006-01-17 02:56:43 UTC (rev 1966)
+++ packages/libfont-ttf-perl/trunk/lib/Font/TTF/Useall.pm 2006-01-17 03:07:20 UTC (rev 1967)
@@ -1,52 +1,52 @@
-use Font::TTF::Cvt_;
-use Font::TTF::Fpgm;
-use Font::TTF::Glyf;
-use Font::TTF::Hdmx;
-use Font::TTF::Kern;
-use Font::TTF::Loca;
-use Font::TTF::LTSH;
-use Font::TTF::Name;
-use Font::TTF::OS_2;
-use Font::TTF::PCLT;
-use Font::TTF::Post;
-use Font::TTF::Prep;
-use Font::TTF::Vmtx;
-use Font::TTF::AATKern;
-use Font::TTF::AATutils;
-use Font::TTF::Anchor;
-use Font::TTF::Bsln;
-use Font::TTF::Delta;
-use Font::TTF::Fdsc;
-use Font::TTF::Feat;
-use Font::TTF::Fmtx;
-use Font::TTF::GPOS;
-use Font::TTF::Mort;
-use Font::TTF::Prop;
-use Font::TTF::GDEF;
-use Font::TTF::Coverage;
-use Font::TTF::GSUB;
-use Font::TTF::Hhea;
-use Font::TTF::Table;
-use Font::TTF::Ttopen;
-use Font::TTF::Glyph;
-use Font::TTF::Head;
-use Font::TTF::Hmtx;
-use Font::TTF::Vhea;
-use Font::TTF::Cmap;
-use Font::TTF::Utils;
-use Font::TTF::Maxp;
-use Font::TTF::Font;
-use Font::TTF::Kern::ClassArray;
-use Font::TTF::Kern::CompactClassArray;
-use Font::TTF::Kern::OrderedList;
-use Font::TTF::Kern::StateTable;
-use Font::TTF::Kern::Subtable;
-use Font::TTF::Mort::Chain;
-use Font::TTF::Mort::Contextual;
-use Font::TTF::Mort::Insertion;
-use Font::TTF::Mort::Ligature;
-use Font::TTF::Mort::Noncontextual;
-use Font::TTF::Mort::Rearrangement;
-use Font::TTF::Mort::Subtable;
-
-1;
+use Font::TTF::Cvt_;
+use Font::TTF::Fpgm;
+use Font::TTF::Glyf;
+use Font::TTF::Hdmx;
+use Font::TTF::Kern;
+use Font::TTF::Loca;
+use Font::TTF::LTSH;
+use Font::TTF::Name;
+use Font::TTF::OS_2;
+use Font::TTF::PCLT;
+use Font::TTF::Post;
+use Font::TTF::Prep;
+use Font::TTF::Vmtx;
+use Font::TTF::AATKern;
+use Font::TTF::AATutils;
+use Font::TTF::Anchor;
+use Font::TTF::Bsln;
+use Font::TTF::Delta;
+use Font::TTF::Fdsc;
+use Font::TTF::Feat;
+use Font::TTF::Fmtx;
+use Font::TTF::GPOS;
+use Font::TTF::Mort;
+use Font::TTF::Prop;
+use Font::TTF::GDEF;
+use Font::TTF::Coverage;
+use Font::TTF::GSUB;
+use Font::TTF::Hhea;
+use Font::TTF::Table;
+use Font::TTF::Ttopen;
+use Font::TTF::Glyph;
+use Font::TTF::Head;
+use Font::TTF::Hmtx;
+use Font::TTF::Vhea;
+use Font::TTF::Cmap;
+use Font::TTF::Utils;
+use Font::TTF::Maxp;
+use Font::TTF::Font;
+use Font::TTF::Kern::ClassArray;
+use Font::TTF::Kern::CompactClassArray;
+use Font::TTF::Kern::OrderedList;
+use Font::TTF::Kern::StateTable;
+use Font::TTF::Kern::Subtable;
+use Font::TTF::Mort::Chain;
+use Font::TTF::Mort::Contextual;
+use Font::TTF::Mort::Insertion;
+use Font::TTF::Mort::Ligature;
+use Font::TTF::Mort::Noncontextual;
+use Font::TTF::Mort::Rearrangement;
+use Font::TTF::Mort::Subtable;
+
+1;
Modified: packages/libfont-ttf-perl/trunk/lib/Font/TTF/Utils.pm
===================================================================
--- packages/libfont-ttf-perl/trunk/lib/Font/TTF/Utils.pm 2006-01-17 02:56:43 UTC (rev 1966)
+++ packages/libfont-ttf-perl/trunk/lib/Font/TTF/Utils.pm 2006-01-17 03:07:20 UTC (rev 1967)
@@ -1,610 +1,610 @@
-package Font::TTF::Utils;
-
-=head1 NAME
-
-Font::TTF::Utils - Utility functions to save fingers
-
-=head1 DESCRIPTION
-
-Lots of useful functions to save my fingers, especially for trivial tables
-
-=head1 FUNCTIONS
-
-The following functions are exported
-
-=cut
-
-use strict;
-use vars qw(@ISA @EXPORT $VERSION @EXPORT_OK);
-require Exporter;
-
- at ISA = qw(Exporter);
- at EXPORT = qw(TTF_Init_Fields TTF_Read_Fields TTF_Out_Fields TTF_Pack
- TTF_Unpack TTF_word_utf8 TTF_utf8_word TTF_bininfo);
- at EXPORT_OK = (@EXPORT, qw(XML_hexdump));
-$VERSION = 0.0001;
-
-=head2 ($val, $pos) = TTF_Init_Fields ($str, $pos)
-
-Given a field description from the C<DATA> section, creates an absolute entry
-in the fields associative array for the class
-
-=cut
-
-sub TTF_Init_Fields
-{
- my ($str, $pos, $inval) = @_;
- my ($key, $val, $res, $len, $rel);
-
- $str =~ s/\r?\n$//o;
- if ($inval)
- { ($key, $val) = ($str, $inval); }
- else
- { ($key, $val) = split(',\s*', $str); }
- return (undef, undef, 0) unless (defined $key && $key ne "");
- if ($val =~ m/^(\+?)(\d*)(\D+)(\d*)/oi)
- {
- $rel = $1;
- if ($rel eq "+")
- { $pos += $2; }
- elsif ($2 ne "")
- { $pos = $2; }
- $val = $3;
- $len = $4;
- }
- $len = "" unless defined $len;
- $pos = 0 if !defined $pos || $pos eq "";
- $res = "$pos:$val:$len";
- if ($val eq "f" || $val =~ m/^[l]/oi)
- { $pos += 4 * ($len ne "" ? $len : 1); }
- elsif ($val eq "F" || $val =~ m/^[s]/oi)
- { $pos += 2 * ($len ne "" ? $len : 1); }
- else
- { $pos += 1 * ($len ne "" ? $len : 1); }
-
- ($key, $res, $pos);
-}
-
-
-=head2 TTF_Read_Fields($obj, $dat, $fields)
-
-Given a block of data large enough to account for all the fields in a table,
-processes the data block to convert to the values in the objects instance
-variables by name based on the list in the C<DATA> block which has been run
-through C<TTF_Init_Fields>
-
-=cut
-
-sub TTF_Read_Fields
-{
- my ($self, $dat, $fields) = @_;
- my ($pos, $type, $res, $f, $arrlen, $arr, $frac);
-
- foreach $f (keys %{$fields})
- {
- ($pos, $type, $arrlen) = split(':', $fields->{$f});
- $pos = 0 if $pos eq "";
- if ($arrlen ne "")
- { $self->{$f} = [TTF_Unpack("$type$arrlen", substr($dat, $pos))]; }
- else
- { $self->{$f} = TTF_Unpack("$type", substr($dat, $pos)); }
- }
- $self;
-}
-
-
-=head2 TTF_Unpack($fmt, $dat)
-
-A TrueType types equivalent of Perls C<unpack> function. Thus $fmt consists of
-type followed by an optional number of elements to read including *. The type
-may be one of:
-
- c BYTE
- C CHAR
- f FIXED
- F F2DOT14
- l LONG
- L ULONG
- s SHORT
- S USHORT
-
-Note that C<FUNIT>, C<FWORD> and C<UFWORD> are not data types but units.
-
-Returns array of scalar (first element) depending on context
-
-=cut
-
-sub TTF_Unpack
-{
- my ($fmt, $dat) = @_;
- my ($res, $frac, $i, $arrlen, $type, @res);
-
- while ($fmt =~ s/^([cfls])(\d+|\*)?//oi)
- {
- $type = $1;
- $arrlen = $2;
- $arrlen = 1 if !defined $arrlen || $arrlen eq "";
- $arrlen = -1 if $arrlen eq "*";
-
- for ($i = 0; ($arrlen == -1 && $dat ne "") || $i < $arrlen; $i++)
- {
- if ($type eq "f")
- {
- ($res, $frac) = unpack("nn", $dat);
- substr($dat, 0, 4) = "";
- $res -= 65536 if $res > 32767;
- $res += $frac / 65536.;
- }
- elsif ($type eq "F")
- {
- $res = unpack("n", $dat);
- substr($dat, 0, 2) = "";
-# $res -= 65536 if $res >= 32768;
- $frac = $res & 0x3fff;
- $res >>= 14;
- $res -= 4 if $res > 1;
-# $frac -= 16384 if $frac > 8191;
- $res += $frac / 16384.;
- }
- elsif ($type =~ m/^[l]/oi)
- {
- $res = unpack("N", $dat);
- substr($dat, 0, 4) = "";
- $res -= (1 << 32) if ($type eq "l" && $res >= 1 << 31);
- }
- elsif ($type =~ m/^[s]/oi)
- {
- $res = unpack("n", $dat);
- substr($dat, 0, 2) = "";
- $res -= 65536 if ($type eq "s" && $res >= 32768);
- }
- elsif ($type eq "c")
- {
- $res = unpack("c", $dat);
- substr($dat, 0, 1) = "";
- }
- else
- {
- $res = unpack("C", $dat);
- substr($dat, 0, 1) = "";
- }
- push (@res, $res);
- }
- }
- return wantarray ? @res : $res[0];
-}
-
-
-=head2 $dat = TTF_Out_Fields($obj, $fields, $len)
-
-Given the fields table from C<TTF_Init_Fields> writes out the instance variables from
-the object to the filehandle in TTF binary form.
-
-=cut
-
-sub TTF_Out_Fields
-{
- my ($obj, $fields, $len) = @_;
- my ($dat) = "\000" x $len;
- my ($f, $pos, $type, $res, $arr, $arrlen, $frac);
-
- foreach $f (keys %{$fields})
- {
- ($pos, $type, $arrlen) = split(':', $fields->{$f});
- if ($arrlen ne "")
- { $res = TTF_Pack("$type$arrlen", @{$obj->{$f}}); }
- else
- { $res = TTF_Pack("$type", $obj->{$f}); }
- substr($dat, $pos, length($res)) = $res;
- }
- $dat;
-}
-
-
-=head2 $dat = TTF_Pack($fmt, @data)
-
-The TrueType equivalent to Perl's C<pack> function. See details of C<TTF_Unpack>
-for how to work the $fmt string.
-
-=cut
-
-sub TTF_Pack
-{
- my ($fmt, @obj) = @_;
- my ($type, $i, $arrlen, $dat, $res, $frac);
-
- while ($fmt =~ s/^([flsc])(\d+|\*)?//oi)
- {
- $type = $1;
- $arrlen = $2 || "";
- $arrlen = $#obj + 1 if $arrlen eq "*";
- $arrlen = 1 if $arrlen eq "";
-
- for ($i = 0; $i < $arrlen; $i++)
- {
- $res = shift(@obj);
- if ($type eq "f")
- {
- $frac = int(($res - int($res)) * 65536);
- $res = (int($res) << 16) + $frac;
- $dat .= pack("N", $res);
- }
- elsif ($type eq "F")
- {
- $frac = int(($res - int($res)) * 16384);
- $res = (int($res) << 14) + $frac;
- $dat .= pack("n", $res);
- }
- elsif ($type =~ m/^[l]/oi)
- {
- $res += 1 << 32 if ($type eq 'L' && $res < 0);
- $dat .= pack("N", $res);
- }
- elsif ($type =~ m/^[s]/oi)
- {
- $res += 1 << 16 if ($type eq 'S' && $res < 0);
- $dat .= pack("n", $res);
- }
- elsif ($type eq "c")
- { $dat .= pack("c", $res); }
- else
- { $dat .= pack("C", $res); }
- }
- }
- $dat;
-}
-
-
-=head2 ($num, $range, $select, $shift) = TTF_bininfo($num)
-
-Calculates binary search information from a number of elements
-
-=cut
-
-sub TTF_bininfo
-{
- my ($num, $block) = @_;
- my ($range, $select, $shift);
-
- $range = 1;
- for ($select = 0; $range <= $num; $select++)
- { $range *= 2; }
- $select--; $range /= 2;
- $range *= $block;
-
- $shift = $num * $block - $range;
- ($num, $range, $select, $shift);
-}
-
-
-=head2 TTF_word_utf8($str)
-
-Returns the UTF8 form of the 16 bit string, assumed to be in big endian order,
-including surrogate handling
-
-=cut
-
-sub TTF_word_utf8
-{
- my ($str) = @_;
- my ($res, $i);
- my (@dat) = unpack("n*", $str);
-
- return pack("U*", @dat) if ($^V && $^V ge v5.6.0);
- for ($i = 0; $i <= $#dat; $i++)
- {
- my ($dat) = $dat[$i];
- if ($dat < 0x80) # Thanks to Gisle Aas for some of his old code
- { $res .= chr($dat); }
- elsif ($dat < 0x800)
- { $res .= chr(0xC0 | ($dat >> 6)) . chr(0x80 | ($dat & 0x3F)); }
- elsif ($dat >= 0xD800 && $dat < 0xDC00)
- {
- my ($dat1) = $dat[++$i];
- my ($top) = (($dat & 0x3C0) >> 6) + 1;
- $res .= chr(0xF0 | ($top >> 2))
- . chr(0x80 | (($top & 1) << 4) | (($dat & 0x3C) >> 2))
- . chr(0x80 | (($dat & 0x3) << 4) | (($dat1 & 0x3C0) >> 6))
- . chr(0x80 | ($dat1 & 0x3F));
- } else
- { $res .= chr(0xE0 | ($dat >> 12)) . chr(0x80 | (($dat >> 6) & 0x3F))
- . chr(0x80 | ($dat & 0x3F)); }
- }
- $res;
-}
-
-
-=head2 TTF_utf8_word($str)
-
-Returns the 16-bit form in big endian order of the UTF 8 string, including
-surrogate handling to Unicode.
-
-=cut
-
-sub TTF_utf8_word
-{
- my ($str) = @_;
- my ($res);
-
- return pack("n*", unpack("U*", $str)) if ($^V ge v5.6.0);
- $str = "$str"; # copy $str
- while (length($str)) # Thanks to Gisle Aas for some of his old code
- {
- $str =~ s/^[\x80-\xBF]+//o;
- if ($str =~ s/^([\x00-\x7F]+)//o)
- { $res .= pack("n*", unpack("C*", $1)); }
- elsif ($str =~ s/^([\xC0-\xDF])([\x80-\xBF])//o)
- { $res .= pack("n", ((ord($1) & 0x1F) << 6) | (ord($2) & 0x3F)); }
- elsif ($str =~ s/^([\0xE0-\xEF])([\x80-\xBF])([\x80-\xBF])//o)
- { $res .= pack("n", ((ord($1) & 0x0F) << 12)
- | ((ord($2) & 0x3F) << 6)
- | (ord($3) & 0x3F)); }
- elsif ($str =~ s/^([\xF0-\xF7])([\x80-\xBF])([\x80-\xBF])([\x80-\xBF])//o)
- {
- my ($b1, $b2, $b3, $b4) = (ord($1), ord($2), ord($3), ord($4));
- $res .= pack("n", ((($b1 & 0x07) << 8) | (($b2 & 0x3F) << 2)
- | (($b3 & 0x30) >> 4)) + 0xD600); # account for offset
- $res .= pack("n", ((($b3 & 0x0F) << 6) | ($b4 & 0x3F)) + 0xDC00);
- }
- elsif ($str =~ s/^[\xF8-\xFF][\x80-\xBF]*//o)
- { }
- }
- $res;
-}
-
-
-=head2 XML_hexdump($context, $dat)
-
-Dumps out the given data as a sequence of <data> blocks each 16 bytes wide
-
-=cut
-
-sub XML_hexdump
-{
- my ($context, $depth, $dat) = @_;
- my ($fh) = $context->{'fh'};
- my ($i, $len, $out);
-
- $len = length($dat);
- for ($i = 0; $i < $len; $i += 16)
- {
- $out = join(' ', map {sprintf("%02X", ord($_))} (split('', substr($dat, $i, 16))));
- $fh->printf("%s<data addr='%04X'>%s</data>\n", $depth, $i, $out);
- }
-}
-
-
-=head2 XML_outhints
-
-Converts a binary string of hinting code into a textual representation
-
-=cut
-
-{
- my (@hints) = (
- ['SVTCA[0]'], ['SVTCA[1]'], ['SPVTCA[0]'], ['SPVTCA[1]'], ['SFVTCA[0]'], ['SFVTCA[1]'], ['SPVTL[0]'], ['SPVTL[1]'],
- ['SFVTL[0]'], ['SFVTL[1]'], ['SPVFS'], ['SFVFS'], ['GPV'], ['GFV'], ['SVFTPV'], ['ISECT'],
-# 10
- ['SRP0'], ['SRP1'], ['SRP2'], ['SZP0'], ['SZP1'], ['SZP2'], ['SZPS'], ['SLOOP'],
- ['RTG'], ['RTHG'], ['SMD'], ['ELSE'], ['JMPR'], ['SCVTCI'], ['SSWCI'], ['SSW'],
-# 20
- ['DUP'], ['POP'], ['CLEAR'], ['SWAP'], ['DEPTH'], ['CINDEX'], ['MINDEX'], ['ALIGNPTS'],
- [], ['UTP'], ['LOOPCALL'], ['CALL'], ['FDEF'], ['ENDF'], ['MDAP[0]'], ['MDAP[1]'],
-# 30
- ['IUP[0]'], ['IUP[1]'], ['SHP[0]'], ['SHP[1]'], ['SHC[0]'], ['SHC[1]'], ['SHZ[0]'], ['SHZ[1]'],
- ['SHPIX'], ['IP'], ['MSIRP[0]'], ['MSIRP[1]'], ['ALIGNRP'], ['RTDG'], ['MIAP[0]'], ['MIAP[1]'],
-# 40
- ['NPUSHB', -1, 1], ['NPUSHW', -1, 2], ['WS', 0, 0], ['RS', 0, 0], ['WCVTP', 0, 0], ['RCVT', 0, 0], ['GC[0]'], ['GC[1]'],
- ['SCFS'], ['MD[0]'], ['MD[1]'], ['MPPEM'], ['MPS'], ['FLIPON'], ['FLIPOFF'], ['DEBUG'],
-# 50
- ['LT'], ['LTEQ'], ['GT'], ['GTEQ'], ['EQ'], ['NEQ'], ['ODD'], ['EVEN'],
- ['IF'], ['EIF'], ['AND'], ['OR'], ['NOT'], ['DELTAP1'], ['SDB'], ['SDS'],
-# 60
- ['ADD'], ['SUB'], ['DIV'], ['MULT'], ['ABS'], ['NEG'], ['FLOOR'], ['CEILING'],
- ['ROUND[0]'], ['ROUND[1]'], ['ROUND[2]'], ['ROUND[3]'], ['NROUND[0]'], ['NROUND[1]'], ['NROUND[2]'], ['NROUND[3]'],
-# 70
- ['WCVTF'], ['DELTAP2'], ['DELTAP3'], ['DELTAC1'], ['DELTAC2'], ['DELTAC3'], ['SROUND'], ['S45ROUND'],
- ['JROT'], ['JROF'], ['ROFF'], [], ['RUTG'], ['RDTG'], ['SANGW'], [],
-# 80
- ['FLIPPT'], ['FLIPRGON'], ['FLIPRGOFF'], [], [], ['SCANCTRL'], ['SDPVTL[0]'], ['SDPVTL[1]'],
- ['GETINFO'], ['IDEF'], ['ROLL'], ['MAX'], ['MIN'], ['SCANTYPE'], ['INSTCTRL'], [],
-# 90
- [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [],
-# A0
- [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [],
-# B0
- ['PUSHB1', 1, 1], ['PUSHB2', 2, 1], ['PUSHB3', 3, 1], ['PUSHB4', 4, 1], ['PUSHB5', 5, 1], ['PUSHB6', 6, 1], ['PUSHB7', 7, 1], ['PUSHB8', 8, 1],
- ['PUSHW1', 1, 2], ['PUSHW2', 2, 2], ['PUSHW3', 3, 2], ['PUSHW4', 4, 2], ['PUSHW5', 5, 2], ['PUSHW6', 6, 2], ['PUSHW7', 7, 2], ['PUSHW8', 8, 2],
-# C0
- ['MDRP[0]'], ['MDRP[1]'], ['MDRP[2]'], ['MDRP[3]'], ['MDRP[4]'], ['MDRP[5]'], ['MDRP[6]'], ['MDRP[7]'],
- ['MDRP[8]'], ['MDRP[9]'], ['MDRP[A]'], ['MDRP[B]'], ['MDRP[C]'], ['MDRP[D]'], ['MDRP[E]'], ['MDRP[F]'],
-# D0
- ['MDRP[10]'], ['MDRP[11]'], ['MDRP[12]'], ['MDRP[13]'], ['MDRP[14]'], ['MDRP[15]'], ['MDRP[16]'], ['MDRP[17]'],
- ['MDRP[18]'], ['MDRP[19]'], ['MDRP[1A]'], ['MDRP[1B]'], ['MDRP[1C]'], ['MDRP[1D]'], ['MDRP[1E]'], ['MDRP[1F]'],
-# E0
- ['MIRP[0]'], ['MIRP[1]'], ['MIRP[2]'], ['MIRP[3]'], ['MIRP[4]'], ['MIRP[5]'], ['MIRP[6]'], ['MIRP[7]'],
- ['MIRP[8]'], ['MIRP[9]'], ['MIRP[A]'], ['MIRP[B]'], ['MIRP[C]'], ['MIRP[D]'], ['MIRP[E]'], ['MIRP[F]'],
-# F0
- ['MIRP[10]'], ['MIRP[11]'], ['MIRP[12]'], ['MIRP[13]'], ['MIRP[14]'], ['MIRP[15]'], ['MIRP[16]'], ['MIRP[17]'],
- ['MIRP[18]'], ['MIRP[19]'], ['MIRP[1A]'], ['MIRP[1B]'], ['MIRP[1C]'], ['MIRP[1D]'], ['MIRP[1E]'], ['MIRP[1F]']);
-
- my ($i);
- my (%hints) = map { $_->[0] => $i++ if (defined $_->[0]); } @hints;
-
- sub XML_binhint
- {
- my ($dat) = @_;
- my ($len) = length($dat);
- my ($res, $i);
- my ($text, $num, $size);
-
- for ($i = 0; $i < $len; $i++)
- {
- ($text, $num, $size) = @{$hints[ord(substr($dat, $i, 1))]};
- $text = sprintf("UNK[%02X]", ord(substr($dat, $i, 1))) unless defined $text;
- $res .= $text;
- if ($num != 0)
- {
- if ($num < 0)
- {
- $i++;
- my ($nnum) = unpack($num == -1 ? 'C' : 'n', substr($dat, $i, -$num));
- $i += -$num - 1;
- $num = $nnum;
- }
- $res .= "\t" . join(' ', unpack($size == 1 ? 'C*' : 'n*', substr($dat, $i + 1, $num * $size)));
- $i += $num * $size;
- }
- $res .= "\n";
- }
- $res;
- }
-
- sub XML_hintbin
- {
- my ($dat) = @_;
- my ($l, $res, @words, $num);
-
- foreach $l (split(/\s*\n\s*/, $dat))
- {
- @words = split(/\s*/, $l);
- next unless (defined $hints{$words[0]});
- $num = $hints{$words[0]};
- $res .= pack('C', $num);
- if ($hints[$num][1] < 0)
- {
- $res .= pack($hints[$num][1] == -1 ? 'C' : 'n', $#words);
- $res .= pack($hints[$num][2] == 1 ? 'C*' : 'n*', @words[1 .. $#words]);
- }
- elsif ($hints[$num][1] > 0)
- {
- $res .= pack($hints[$num][2] == 1 ? 'C*' : 'n*', @words[1 .. $hints[$num][1]]);
- }
- }
- $res;
- }
-}
-
-
-=head2 make_circle($f, $cmap, [$dia, $sb, $opts])
-
-Adds a dotted circle to a font. This function is very configurable. The
-parameters passed in are:
-
-=over 4
-
-=item $f
-
-Font to work with. This is required.
-
-=item $cmap
-
-A cmap table (not the 'val' sub-element of a cmap) to add the glyph too. Optional.
-
-=item $dia
-
-Optional diameter for the main circle. Defaults to 80% em
-
-=item $sb
-
-Side bearing. The left and right side-bearings are always the same. This value
-defaults to 10% em.
-
-=back
-
-There are various options to control all sorts of interesting aspects of the circle
-
-=over 4
-
-=item numDots
-
-Number of dots in the circle
-
-=item numPoints
-
-Number of curve points to use to create each dot
-
-=item uid
-
-Unicode reference to store this glyph under in the cmap. Defaults to 0x25CC
-
-=item pname
-
-Postscript name to give the glyph. Defaults to uni25CC.
-
-=item -dRadius
-
-Radius of each dot.
-
-=back
-
-=cut
-
-sub make_circle
-{
- my ($font, $cmap, $dia, $sb, %opts) = @_;
- my ($upem) = $font->{'head'}{'unitsPerEm'};
- my ($glyph) = Font::TTF::Glyph->new('PARENT' => $font, 'read' => 2);
- my ($PI) = 3.1415926535;
- my ($R, $r, $xorg, $yorg);
- my ($i, $j, $numg, $maxp);
- my ($numc) = $opts{'-numDots'} || 16;
- my ($nump) = ($opts{'-numPoints'} * 2) || 8;
- my ($uid) = $opts{'-uid'} || 0x25CC;
- my ($pname) = $opts{'-pname'} || 'uni25CC';
-
- $dia ||= $upem * .8; # .95 to fit exactly
- $sb ||= $upem * .1;
- $R = $dia / 2;
- $r = $opts{'-dRadius'} || ($R * .1);
- ($xorg, $yorg) = ($R + $r, $R);
-
- $xorg += $sb;
- $font->{'post'}->read;
- $font->{'glyf'}->read;
- for ($i = 0; $i < $numc; $i++)
- {
- my ($pxorg, $pyorg) = ($xorg + $R * cos(2 * $PI * $i / $numc),
- $yorg + $R * sin(2 * $PI * $i / $numc));
- for ($j = 0; $j < $nump; $j++)
- {
- push (@{$glyph->{'x'}}, int ($pxorg + ($j & 1 ? 1/cos(2*$PI/$nump) : 1) * $r * cos(2 * $PI * $j / $nump)));
- push (@{$glyph->{'y'}}, int ($pyorg + ($j & 1 ? 1/cos(2*$PI/$nump) : 1) * $r * sin(2 * $PI * $j / $nump)));
- push (@{$glyph->{'flags'}}, $j & 1 ? 0 : 1);
- }
- push (@{$glyph->{'endPoints'}}, $#{$glyph->{'x'}});
- }
- $glyph->{'numberOfContours'} = $#{$glyph->{'endPoints'}} + 1;
- $glyph->{'numPoints'} = $#{$glyph->{'x'}} + 1;
- $glyph->update;
- $numg = $font->{'maxp'}{'numGlyphs'};
- $font->{'maxp'}->read->{'numGlyphs'}++;
-
- $font->{'hmtx'}{'advance'}[$numg] = int($xorg + $R + $r + $sb + .5);
- $font->{'hmtx'}{'lsb'}[$numg] = int($xorg - $R - $r + .5);
- $font->{'loca'}{'glyphs'}[$numg] = $glyph;
- $cmap->{'val'}{$uid} = $numg if ($cmap);
- $font->{'post'}{'VAL'}[$numg] = $pname;
- delete $font->{'hdmx'};
- delete $font->{'VDMX'};
- delete $font->{'LTSH'};
-
- $font->tables_do(sub {$_[0]->dirty;});
- $font->update;
- return ($numg - 1);
-}
-
-
-1;
-
-=head1 BUGS
-
-No known bugs
-
-=head1 AUTHOR
-
-Martin Hosken Martin_Hosken at sil.org. See L<Font::TTF::Font> for copyright and
-licensing.
-
-=cut
-
+package Font::TTF::Utils;
+
+=head1 NAME
+
+Font::TTF::Utils - Utility functions to save fingers
+
+=head1 DESCRIPTION
+
+Lots of useful functions to save my fingers, especially for trivial tables
+
+=head1 FUNCTIONS
+
+The following functions are exported
+
+=cut
+
+use strict;
+use vars qw(@ISA @EXPORT $VERSION @EXPORT_OK);
+require Exporter;
+
+ at ISA = qw(Exporter);
+ at EXPORT = qw(TTF_Init_Fields TTF_Read_Fields TTF_Out_Fields TTF_Pack
+ TTF_Unpack TTF_word_utf8 TTF_utf8_word TTF_bininfo);
+ at EXPORT_OK = (@EXPORT, qw(XML_hexdump));
+$VERSION = 0.0001;
+
+=head2 ($val, $pos) = TTF_Init_Fields ($str, $pos)
+
+Given a field description from the C<DATA> section, creates an absolute entry
+in the fields associative array for the class
+
+=cut
+
+sub TTF_Init_Fields
+{
+ my ($str, $pos, $inval) = @_;
+ my ($key, $val, $res, $len, $rel);
+
+ $str =~ s/\r?\n$//o;
+ if ($inval)
+ { ($key, $val) = ($str, $inval); }
+ else
+ { ($key, $val) = split(',\s*', $str); }
+ return (undef, undef, 0) unless (defined $key && $key ne "");
+ if ($val =~ m/^(\+?)(\d*)(\D+)(\d*)/oi)
+ {
+ $rel = $1;
+ if ($rel eq "+")
+ { $pos += $2; }
+ elsif ($2 ne "")
+ { $pos = $2; }
+ $val = $3;
+ $len = $4;
+ }
+ $len = "" unless defined $len;
+ $pos = 0 if !defined $pos || $pos eq "";
+ $res = "$pos:$val:$len";
+ if ($val eq "f" || $val =~ m/^[l]/oi)
+ { $pos += 4 * ($len ne "" ? $len : 1); }
+ elsif ($val eq "F" || $val =~ m/^[s]/oi)
+ { $pos += 2 * ($len ne "" ? $len : 1); }
+ else
+ { $pos += 1 * ($len ne "" ? $len : 1); }
+
+ ($key, $res, $pos);
+}
+
+
+=head2 TTF_Read_Fields($obj, $dat, $fields)
+
+Given a block of data large enough to account for all the fields in a table,
+processes the data block to convert to the values in the objects instance
+variables by name based on the list in the C<DATA> block which has been run
+through C<TTF_Init_Fields>
+
+=cut
+
+sub TTF_Read_Fields
+{
+ my ($self, $dat, $fields) = @_;
+ my ($pos, $type, $res, $f, $arrlen, $arr, $frac);
+
+ foreach $f (keys %{$fields})
+ {
+ ($pos, $type, $arrlen) = split(':', $fields->{$f});
+ $pos = 0 if $pos eq "";
+ if ($arrlen ne "")
+ { $self->{$f} = [TTF_Unpack("$type$arrlen", substr($dat, $pos))]; }
+ else
+ { $self->{$f} = TTF_Unpack("$type", substr($dat, $pos)); }
+ }
+ $self;
+}
+
+
+=head2 TTF_Unpack($fmt, $dat)
+
+A TrueType types equivalent of Perls C<unpack> function. Thus $fmt consists of
+type followed by an optional number of elements to read including *. The type
+may be one of:
+
+ c BYTE
+ C CHAR
+ f FIXED
+ F F2DOT14
+ l LONG
+ L ULONG
+ s SHORT
+ S USHORT
+
+Note that C<FUNIT>, C<FWORD> and C<UFWORD> are not data types but units.
+
+Returns array of scalar (first element) depending on context
+
+=cut
+
+sub TTF_Unpack
+{
+ my ($fmt, $dat) = @_;
+ my ($res, $frac, $i, $arrlen, $type, @res);
+
+ while ($fmt =~ s/^([cfls])(\d+|\*)?//oi)
+ {
+ $type = $1;
+ $arrlen = $2;
+ $arrlen = 1 if !defined $arrlen || $arrlen eq "";
+ $arrlen = -1 if $arrlen eq "*";
+
+ for ($i = 0; ($arrlen == -1 && $dat ne "") || $i < $arrlen; $i++)
+ {
+ if ($type eq "f")
+ {
+ ($res, $frac) = unpack("nn", $dat);
+ substr($dat, 0, 4) = "";
+ $res -= 65536 if $res > 32767;
+ $res += $frac / 65536.;
+ }
+ elsif ($type eq "F")
+ {
+ $res = unpack("n", $dat);
+ substr($dat, 0, 2) = "";
+# $res -= 65536 if $res >= 32768;
+ $frac = $res & 0x3fff;
+ $res >>= 14;
+ $res -= 4 if $res > 1;
+# $frac -= 16384 if $frac > 8191;
+ $res += $frac / 16384.;
+ }
+ elsif ($type =~ m/^[l]/oi)
+ {
+ $res = unpack("N", $dat);
+ substr($dat, 0, 4) = "";
+ $res -= (1 << 32) if ($type eq "l" && $res >= 1 << 31);
+ }
+ elsif ($type =~ m/^[s]/oi)
+ {
+ $res = unpack("n", $dat);
+ substr($dat, 0, 2) = "";
+ $res -= 65536 if ($type eq "s" && $res >= 32768);
+ }
+ elsif ($type eq "c")
+ {
+ $res = unpack("c", $dat);
+ substr($dat, 0, 1) = "";
+ }
+ else
+ {
+ $res = unpack("C", $dat);
+ substr($dat, 0, 1) = "";
+ }
+ push (@res, $res);
+ }
+ }
+ return wantarray ? @res : $res[0];
+}
+
+
+=head2 $dat = TTF_Out_Fields($obj, $fields, $len)
+
+Given the fields table from C<TTF_Init_Fields> writes out the instance variables from
+the object to the filehandle in TTF binary form.
+
+=cut
+
+sub TTF_Out_Fields
+{
+ my ($obj, $fields, $len) = @_;
+ my ($dat) = "\000" x $len;
+ my ($f, $pos, $type, $res, $arr, $arrlen, $frac);
+
+ foreach $f (keys %{$fields})
+ {
+ ($pos, $type, $arrlen) = split(':', $fields->{$f});
+ if ($arrlen ne "")
+ { $res = TTF_Pack("$type$arrlen", @{$obj->{$f}}); }
+ else
+ { $res = TTF_Pack("$type", $obj->{$f}); }
+ substr($dat, $pos, length($res)) = $res;
+ }
+ $dat;
+}
+
+
+=head2 $dat = TTF_Pack($fmt, @data)
+
+The TrueType equivalent to Perl's C<pack> function. See details of C<TTF_Unpack>
+for how to work the $fmt string.
+
+=cut
+
+sub TTF_Pack
+{
+ my ($fmt, @obj) = @_;
+ my ($type, $i, $arrlen, $dat, $res, $frac);
+
+ while ($fmt =~ s/^([flsc])(\d+|\*)?//oi)
+ {
+ $type = $1;
+ $arrlen = $2 || "";
+ $arrlen = $#obj + 1 if $arrlen eq "*";
+ $arrlen = 1 if $arrlen eq "";
+
+ for ($i = 0; $i < $arrlen; $i++)
+ {
+ $res = shift(@obj);
+ if ($type eq "f")
+ {
+ $frac = int(($res - int($res)) * 65536);
+ $res = (int($res) << 16) + $frac;
+ $dat .= pack("N", $res);
+ }
+ elsif ($type eq "F")
+ {
+ $frac = int(($res - int($res)) * 16384);
+ $res = (int($res) << 14) + $frac;
+ $dat .= pack("n", $res);
+ }
+ elsif ($type =~ m/^[l]/oi)
+ {
+ $res += 1 << 32 if ($type eq 'L' && $res < 0);
+ $dat .= pack("N", $res);
+ }
+ elsif ($type =~ m/^[s]/oi)
+ {
+ $res += 1 << 16 if ($type eq 'S' && $res < 0);
+ $dat .= pack("n", $res);
+ }
+ elsif ($type eq "c")
+ { $dat .= pack("c", $res); }
+ else
+ { $dat .= pack("C", $res); }
+ }
+ }
+ $dat;
+}
+
+
+=head2 ($num, $range, $select, $shift) = TTF_bininfo($num)
+
+Calculates binary search information from a number of elements
+
+=cut
+
+sub TTF_bininfo
+{
+ my ($num, $block) = @_;
+ my ($range, $select, $shift);
+
+ $range = 1;
+ for ($select = 0; $range <= $num; $select++)
+ { $range *= 2; }
+ $select--; $range /= 2;
+ $range *= $block;
+
+ $shift = $num * $block - $range;
+ ($num, $range, $select, $shift);
+}
+
+
+=head2 TTF_word_utf8($str)
+
+Returns the UTF8 form of the 16 bit string, assumed to be in big endian order,
+including surrogate handling
+
+=cut
+
+sub TTF_word_utf8
+{
+ my ($str) = @_;
+ my ($res, $i);
+ my (@dat) = unpack("n*", $str);
+
+ return pack("U*", @dat) if ($^V && $^V ge v5.6.0);
+ for ($i = 0; $i <= $#dat; $i++)
+ {
+ my ($dat) = $dat[$i];
+ if ($dat < 0x80) # Thanks to Gisle Aas for some of his old code
+ { $res .= chr($dat); }
+ elsif ($dat < 0x800)
+ { $res .= chr(0xC0 | ($dat >> 6)) . chr(0x80 | ($dat & 0x3F)); }
+ elsif ($dat >= 0xD800 && $dat < 0xDC00)
+ {
+ my ($dat1) = $dat[++$i];
+ my ($top) = (($dat & 0x3C0) >> 6) + 1;
+ $res .= chr(0xF0 | ($top >> 2))
+ . chr(0x80 | (($top & 1) << 4) | (($dat & 0x3C) >> 2))
+ . chr(0x80 | (($dat & 0x3) << 4) | (($dat1 & 0x3C0) >> 6))
+ . chr(0x80 | ($dat1 & 0x3F));
+ } else
+ { $res .= chr(0xE0 | ($dat >> 12)) . chr(0x80 | (($dat >> 6) & 0x3F))
+ . chr(0x80 | ($dat & 0x3F)); }
+ }
+ $res;
+}
+
+
+=head2 TTF_utf8_word($str)
+
+Returns the 16-bit form in big endian order of the UTF 8 string, including
+surrogate handling to Unicode.
+
+=cut
+
+sub TTF_utf8_word
+{
+ my ($str) = @_;
+ my ($res);
+
+ return pack("n*", unpack("U*", $str)) if ($^V ge v5.6.0);
+ $str = "$str"; # copy $str
+ while (length($str)) # Thanks to Gisle Aas for some of his old code
+ {
+ $str =~ s/^[\x80-\xBF]+//o;
+ if ($str =~ s/^([\x00-\x7F]+)//o)
+ { $res .= pack("n*", unpack("C*", $1)); }
+ elsif ($str =~ s/^([\xC0-\xDF])([\x80-\xBF])//o)
+ { $res .= pack("n", ((ord($1) & 0x1F) << 6) | (ord($2) & 0x3F)); }
+ elsif ($str =~ s/^([\0xE0-\xEF])([\x80-\xBF])([\x80-\xBF])//o)
+ { $res .= pack("n", ((ord($1) & 0x0F) << 12)
+ | ((ord($2) & 0x3F) << 6)
+ | (ord($3) & 0x3F)); }
+ elsif ($str =~ s/^([\xF0-\xF7])([\x80-\xBF])([\x80-\xBF])([\x80-\xBF])//o)
+ {
+ my ($b1, $b2, $b3, $b4) = (ord($1), ord($2), ord($3), ord($4));
+ $res .= pack("n", ((($b1 & 0x07) << 8) | (($b2 & 0x3F) << 2)
+ | (($b3 & 0x30) >> 4)) + 0xD600); # account for offset
+ $res .= pack("n", ((($b3 & 0x0F) << 6) | ($b4 & 0x3F)) + 0xDC00);
+ }
+ elsif ($str =~ s/^[\xF8-\xFF][\x80-\xBF]*//o)
+ { }
+ }
+ $res;
+}
+
+
+=head2 XML_hexdump($context, $dat)
+
+Dumps out the given data as a sequence of <data> blocks each 16 bytes wide
+
+=cut
+
+sub XML_hexdump
+{
+ my ($context, $depth, $dat) = @_;
+ my ($fh) = $context->{'fh'};
+ my ($i, $len, $out);
+
+ $len = length($dat);
+ for ($i = 0; $i < $len; $i += 16)
+ {
+ $out = join(' ', map {sprintf("%02X", ord($_))} (split('', substr($dat, $i, 16))));
+ $fh->printf("%s<data addr='%04X'>%s</data>\n", $depth, $i, $out);
+ }
+}
+
+
+=head2 XML_outhints
+
+Converts a binary string of hinting code into a textual representation
+
+=cut
+
+{
+ my (@hints) = (
+ ['SVTCA[0]'], ['SVTCA[1]'], ['SPVTCA[0]'], ['SPVTCA[1]'], ['SFVTCA[0]'], ['SFVTCA[1]'], ['SPVTL[0]'], ['SPVTL[1]'],
+ ['SFVTL[0]'], ['SFVTL[1]'], ['SPVFS'], ['SFVFS'], ['GPV'], ['GFV'], ['SVFTPV'], ['ISECT'],
+# 10
+ ['SRP0'], ['SRP1'], ['SRP2'], ['SZP0'], ['SZP1'], ['SZP2'], ['SZPS'], ['SLOOP'],
+ ['RTG'], ['RTHG'], ['SMD'], ['ELSE'], ['JMPR'], ['SCVTCI'], ['SSWCI'], ['SSW'],
+# 20
+ ['DUP'], ['POP'], ['CLEAR'], ['SWAP'], ['DEPTH'], ['CINDEX'], ['MINDEX'], ['ALIGNPTS'],
+ [], ['UTP'], ['LOOPCALL'], ['CALL'], ['FDEF'], ['ENDF'], ['MDAP[0]'], ['MDAP[1]'],
+# 30
+ ['IUP[0]'], ['IUP[1]'], ['SHP[0]'], ['SHP[1]'], ['SHC[0]'], ['SHC[1]'], ['SHZ[0]'], ['SHZ[1]'],
+ ['SHPIX'], ['IP'], ['MSIRP[0]'], ['MSIRP[1]'], ['ALIGNRP'], ['RTDG'], ['MIAP[0]'], ['MIAP[1]'],
+# 40
+ ['NPUSHB', -1, 1], ['NPUSHW', -1, 2], ['WS', 0, 0], ['RS', 0, 0], ['WCVTP', 0, 0], ['RCVT', 0, 0], ['GC[0]'], ['GC[1]'],
+ ['SCFS'], ['MD[0]'], ['MD[1]'], ['MPPEM'], ['MPS'], ['FLIPON'], ['FLIPOFF'], ['DEBUG'],
+# 50
+ ['LT'], ['LTEQ'], ['GT'], ['GTEQ'], ['EQ'], ['NEQ'], ['ODD'], ['EVEN'],
+ ['IF'], ['EIF'], ['AND'], ['OR'], ['NOT'], ['DELTAP1'], ['SDB'], ['SDS'],
+# 60
+ ['ADD'], ['SUB'], ['DIV'], ['MULT'], ['ABS'], ['NEG'], ['FLOOR'], ['CEILING'],
+ ['ROUND[0]'], ['ROUND[1]'], ['ROUND[2]'], ['ROUND[3]'], ['NROUND[0]'], ['NROUND[1]'], ['NROUND[2]'], ['NROUND[3]'],
+# 70
+ ['WCVTF'], ['DELTAP2'], ['DELTAP3'], ['DELTAC1'], ['DELTAC2'], ['DELTAC3'], ['SROUND'], ['S45ROUND'],
+ ['JROT'], ['JROF'], ['ROFF'], [], ['RUTG'], ['RDTG'], ['SANGW'], [],
+# 80
+ ['FLIPPT'], ['FLIPRGON'], ['FLIPRGOFF'], [], [], ['SCANCTRL'], ['SDPVTL[0]'], ['SDPVTL[1]'],
+ ['GETINFO'], ['IDEF'], ['ROLL'], ['MAX'], ['MIN'], ['SCANTYPE'], ['INSTCTRL'], [],
+# 90
+ [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [],
+# A0
+ [], [], [], [], [], [], [], [], [], [], [], [], [], [], [], [],
+# B0
+ ['PUSHB1', 1, 1], ['PUSHB2', 2, 1], ['PUSHB3', 3, 1], ['PUSHB4', 4, 1], ['PUSHB5', 5, 1], ['PUSHB6', 6, 1], ['PUSHB7', 7, 1], ['PUSHB8', 8, 1],
+ ['PUSHW1', 1, 2], ['PUSHW2', 2, 2], ['PUSHW3', 3, 2], ['PUSHW4', 4, 2], ['PUSHW5', 5, 2], ['PUSHW6', 6, 2], ['PUSHW7', 7, 2], ['PUSHW8', 8, 2],
+# C0
+ ['MDRP[0]'], ['MDRP[1]'], ['MDRP[2]'], ['MDRP[3]'], ['MDRP[4]'], ['MDRP[5]'], ['MDRP[6]'], ['MDRP[7]'],
+ ['MDRP[8]'], ['MDRP[9]'], ['MDRP[A]'], ['MDRP[B]'], ['MDRP[C]'], ['MDRP[D]'], ['MDRP[E]'], ['MDRP[F]'],
+# D0
+ ['MDRP[10]'], ['MDRP[11]'], ['MDRP[12]'], ['MDRP[13]'], ['MDRP[14]'], ['MDRP[15]'], ['MDRP[16]'], ['MDRP[17]'],
+ ['MDRP[18]'], ['MDRP[19]'], ['MDRP[1A]'], ['MDRP[1B]'], ['MDRP[1C]'], ['MDRP[1D]'], ['MDRP[1E]'], ['MDRP[1F]'],
+# E0
+ ['MIRP[0]'], ['MIRP[1]'], ['MIRP[2]'], ['MIRP[3]'], ['MIRP[4]'], ['MIRP[5]'], ['MIRP[6]'], ['MIRP[7]'],
+ ['MIRP[8]'], ['MIRP[9]'], ['MIRP[A]'], ['MIRP[B]'], ['MIRP[C]'], ['MIRP[D]'], ['MIRP[E]'], ['MIRP[F]'],
+# F0
+ ['MIRP[10]'], ['MIRP[11]'], ['MIRP[12]'], ['MIRP[13]'], ['MIRP[14]'], ['MIRP[15]'], ['MIRP[16]'], ['MIRP[17]'],
+ ['MIRP[18]'], ['MIRP[19]'], ['MIRP[1A]'], ['MIRP[1B]'], ['MIRP[1C]'], ['MIRP[1D]'], ['MIRP[1E]'], ['MIRP[1F]']);
+
+ my ($i);
+ my (%hints) = map { $_->[0] => $i++ if (defined $_->[0]); } @hints;
+
+ sub XML_binhint
+ {
+ my ($dat) = @_;
+ my ($len) = length($dat);
+ my ($res, $i);
+ my ($text, $num, $size);
+
+ for ($i = 0; $i < $len; $i++)
+ {
+ ($text, $num, $size) = @{$hints[ord(substr($dat, $i, 1))]};
+ $text = sprintf("UNK[%02X]", ord(substr($dat, $i, 1))) unless defined $text;
+ $res .= $text;
+ if ($num != 0)
+ {
+ if ($num < 0)
+ {
+ $i++;
+ my ($nnum) = unpack($num == -1 ? 'C' : 'n', substr($dat, $i, -$num));
+ $i += -$num - 1;
+ $num = $nnum;
+ }
+ $res .= "\t" . join(' ', unpack($size == 1 ? 'C*' : 'n*', substr($dat, $i + 1, $num * $size)));
+ $i += $num * $size;
+ }
+ $res .= "\n";
+ }
+ $res;
+ }
+
+ sub XML_hintbin
+ {
+ my ($dat) = @_;
+ my ($l, $res, @words, $num);
+
+ foreach $l (split(/\s*\n\s*/, $dat))
+ {
+ @words = split(/\s*/, $l);
+ next unless (defined $hints{$words[0]});
+ $num = $hints{$words[0]};
+ $res .= pack('C', $num);
+ if ($hints[$num][1] < 0)
+ {
+ $res .= pack($hints[$num][1] == -1 ? 'C' : 'n', $#words);
+ $res .= pack($hints[$num][2] == 1 ? 'C*' : 'n*', @words[1 .. $#words]);
+ }
+ elsif ($hints[$num][1] > 0)
+ {
+ $res .= pack($hints[$num][2] == 1 ? 'C*' : 'n*', @words[1 .. $hints[$num][1]]);
+ }
+ }
+ $res;
+ }
+}
+
+
+=head2 make_circle($f, $cmap, [$dia, $sb, $opts])
+
+Adds a dotted circle to a font. This function is very configurable. The
+parameters passed in are:
+
+=over 4
+
+=item $f
+
+Font to work with. This is required.
+
+=item $cmap
+
+A cmap table (not the 'val' sub-element of a cmap) to add the glyph too. Optional.
+
+=item $dia
+
+Optional diameter for the main circle. Defaults to 80% em
+
+=item $sb
+
+Side bearing. The left and right side-bearings are always the same. This value
+defaults to 10% em.
+
+=back
+
+There are various options to control all sorts of interesting aspects of the circle
+
+=over 4
+
+=item numDots
+
+Number of dots in the circle
+
+=item numPoints
+
+Number of curve points to use to create each dot
+
+=item uid
+
+Unicode reference to store this glyph under in the cmap. Defaults to 0x25CC
+
+=item pname
+
+Postscript name to give the glyph. Defaults to uni25CC.
+
+=item -dRadius
+
+Radius of each dot.
+
+=back
+
+=cut
+
+sub make_circle
+{
+ my ($font, $cmap, $dia, $sb, %opts) = @_;
+ my ($upem) = $font->{'head'}{'unitsPerEm'};
+ my ($glyph) = Font::TTF::Glyph->new('PARENT' => $font, 'read' => 2);
+ my ($PI) = 3.1415926535;
+ my ($R, $r, $xorg, $yorg);
+ my ($i, $j, $numg, $maxp);
+ my ($numc) = $opts{'-numDots'} || 16;
+ my ($nump) = ($opts{'-numPoints'} * 2) || 8;
+ my ($uid) = $opts{'-uid'} || 0x25CC;
+ my ($pname) = $opts{'-pname'} || 'uni25CC';
+
+ $dia ||= $upem * .8; # .95 to fit exactly
+ $sb ||= $upem * .1;
+ $R = $dia / 2;
+ $r = $opts{'-dRadius'} || ($R * .1);
+ ($xorg, $yorg) = ($R + $r, $R);
+
+ $xorg += $sb;
+ $font->{'post'}->read;
+ $font->{'glyf'}->read;
+ for ($i = 0; $i < $numc; $i++)
+ {
+ my ($pxorg, $pyorg) = ($xorg + $R * cos(2 * $PI * $i / $numc),
+ $yorg + $R * sin(2 * $PI * $i / $numc));
+ for ($j = 0; $j < $nump; $j++)
+ {
+ push (@{$glyph->{'x'}}, int ($pxorg + ($j & 1 ? 1/cos(2*$PI/$nump) : 1) * $r * cos(2 * $PI * $j / $nump)));
+ push (@{$glyph->{'y'}}, int ($pyorg + ($j & 1 ? 1/cos(2*$PI/$nump) : 1) * $r * sin(2 * $PI * $j / $nump)));
+ push (@{$glyph->{'flags'}}, $j & 1 ? 0 : 1);
+ }
+ push (@{$glyph->{'endPoints'}}, $#{$glyph->{'x'}});
+ }
+ $glyph->{'numberOfContours'} = $#{$glyph->{'endPoints'}} + 1;
+ $glyph->{'numPoints'} = $#{$glyph->{'x'}} + 1;
+ $glyph->update;
+ $numg = $font->{'maxp'}{'numGlyphs'};
+ $font->{'maxp'}->read->{'numGlyphs'}++;
+
+ $font->{'hmtx'}{'advance'}[$numg] = int($xorg + $R + $r + $sb + .5);
+ $font->{'hmtx'}{'lsb'}[$numg] = int($xorg - $R - $r + .5);
+ $font->{'loca'}{'glyphs'}[$numg] = $glyph;
+ $cmap->{'val'}{$uid} = $numg if ($cmap);
+ $font->{'post'}{'VAL'}[$numg] = $pname;
+ delete $font->{'hdmx'};
+ delete $font->{'VDMX'};
+ delete $font->{'LTSH'};
+
+ $font->tables_do(sub {$_[0]->dirty;});
+ $font->update;
+ return ($numg - 1);
+}
+
+
+1;
+
+=head1 BUGS
+
+No known bugs
+
+=head1 AUTHOR
+
+Martin Hosken Martin_Hosken at sil.org. See L<Font::TTF::Font> for copyright and
+licensing.
+
+=cut
+
Modified: packages/libfont-ttf-perl/trunk/lib/Font/TTF/Vhea.pm
===================================================================
--- packages/libfont-ttf-perl/trunk/lib/Font/TTF/Vhea.pm 2006-01-17 02:56:43 UTC (rev 1966)
+++ packages/libfont-ttf-perl/trunk/lib/Font/TTF/Vhea.pm 2006-01-17 03:07:20 UTC (rev 1967)
@@ -1,159 +1,159 @@
-package Font::TTF::Vhea;
-
-=head1 NAME
-
-Font::TTF::Vhea - Vertical Header table
-
-=head1 DESCRIPTION
-
-This is a simple table with just standards specified instance variables
-
-=head1 INSTANCE VARIABLES
-
- version
- Ascender
- Descender
- LineGap
- advanceHeightMax
- minTopSideBearing
- minBottomSideBearing
- yMaxExtent
- caretSlopeRise
- caretSlopeRun
- metricDataFormat
- numberOfVMetrics
-
-
-=head1 METHODS
-
-=cut
-
-use strict;
-use vars qw(@ISA %fields @field_info);
-
-require Font::TTF::Table;
-use Font::TTF::Utils;
-
- at ISA = qw(Font::TTF::Table);
- at field_info = (
- 'version' => 'f',
- 'Ascender' => 's',
- 'Descender' => 's',
- 'LineGap' => 's',
- 'advanceHeightMax' => 'S',
- 'minTopSideBearing' => 's',
- 'minBottomSideBearing' => 's',
- 'yMaxExtent' => 's',
- 'caretSlopeRise' => 's',
- 'caretSlopeRun' => 's',
- 'metricDataFormat' => '+10s',
- 'numberOfVMetrics' => 's');
-
-sub init
-{
- my ($k, $v, $c, $i);
- for ($i = 0; $i < $#field_info; $i += 2)
- {
- ($k, $v, $c) = TTF_Init_Fields($field_info[$i], $c, $field_info[$i + 1]);
- next unless defined $k && $k ne "";
- $fields{$k} = $v;
- }
-}
-
-
-=head2 $t->read
-
-Reads the table into memory as instance variables
-
-=cut
-
-sub read
-{
- my ($self) = @_;
- my ($dat);
-
- $self->SUPER::read or return $self;
- init unless defined $fields{'Ascender'};
- $self->{' INFILE'}->read($dat, 36);
-
- TTF_Read_Fields($self, $dat, \%fields);
- $self;
-}
-
-
-=head2 $t->out($fh)
-
-Writes the table to a file either from memory or by copying.
-
-=cut
-
-sub out
-{
- my ($self, $fh) = @_;
-
- return $self->SUPER::out($fh) unless $self->{' read'};
-
- $self->{'numberOfVMetrics'} = $self->{' PARENT'}{'vmtx'}->numMetrics || $self->{'numberOfVMetrics'};
- $fh->print(TTF_Out_Fields($self, \%fields, 36));
- $self;
-}
-
-
-=head2 $t->update
-
-Updates various parameters in the hhea table from the hmtx table, assuming
-the C<hmtx> table is dirty.
-
-=cut
-
-sub update
-{
- my ($self) = @_;
- my ($vmtx) = $self->{' PARENT'}{'vmtx'};
- my ($glyphs);
- my ($num);
- my ($i, $maw, $mlsb, $mrsb, $mext, $aw, $lsb, $ext);
-
- return undef unless ($self->SUPER::update);
- return undef unless (defined $vmtx && defined $self->{' PARENT'}{'loca'});
- $vmtx->read->update;
- $self->{' PARENT'}{'loca'}->read->update;
- $glyphs = $self->{' PARENT'}{'loca'}{'glyphs'};
- $num = $self->{' PARENT'}{'maxp'}{'numGlyphs'};
-
- for ($i = 0; $i < $num; $i++)
- {
- $aw = $vmtx->{'advance'}[$i];
- $lsb = $vmtx->{'top'}[$i];
- if (defined $glyphs->[$i])
- { $ext = $lsb + $glyphs->[$i]->read->{'yMax'} - $glyphs->[$i]{'yMin'}; }
- else
- { $ext = $aw; }
- $maw = $aw if ($aw > $maw);
- $mlsb = $lsb if ($lsb < $mlsb or $i == 0);
- $mrsb = $aw - $ext if ($aw - $ext < $mrsb or $i == 0);
- $mext = $ext if ($ext > $mext);
- }
- $self->{'advanceHeightMax'} = $maw;
- $self->{'minTopSideBearing'} = $mlsb;
- $self->{'minBottomSideBearing'} = $mrsb;
- $self->{'yMaxExtent'} = $mext;
- $self->{'numberOfVMetrics'} = $vmtx->numMetrics;
- $self;
-}
-
-
-1;
-
-
-=head1 BUGS
-
-None known
-
-=head1 AUTHOR
-
-Martin Hosken Martin_Hosken at sil.org. See L<Font::TTF::Font> for copyright and
-licensing.
-
-=cut
-
+package Font::TTF::Vhea;
+
+=head1 NAME
+
+Font::TTF::Vhea - Vertical Header table
+
+=head1 DESCRIPTION
+
+This is a simple table with just standards specified instance variables
+
+=head1 INSTANCE VARIABLES
+
+ version
+ Ascender
+ Descender
+ LineGap
+ advanceHeightMax
+ minTopSideBearing
+ minBottomSideBearing
+ yMaxExtent
+ caretSlopeRise
+ caretSlopeRun
+ metricDataFormat
+ numberOfVMetrics
+
+
+=head1 METHODS
+
+=cut
+
+use strict;
+use vars qw(@ISA %fields @field_info);
+
+require Font::TTF::Table;
+use Font::TTF::Utils;
+
+ at ISA = qw(Font::TTF::Table);
+ at field_info = (
+ 'version' => 'f',
+ 'Ascender' => 's',
+ 'Descender' => 's',
+ 'LineGap' => 's',
+ 'advanceHeightMax' => 'S',
+ 'minTopSideBearing' => 's',
+ 'minBottomSideBearing' => 's',
+ 'yMaxExtent' => 's',
+ 'caretSlopeRise' => 's',
+ 'caretSlopeRun' => 's',
+ 'metricDataFormat' => '+10s',
+ 'numberOfVMetrics' => 's');
+
+sub init
+{
+ my ($k, $v, $c, $i);
+ for ($i = 0; $i < $#field_info; $i += 2)
+ {
+ ($k, $v, $c) = TTF_Init_Fields($field_info[$i], $c, $field_info[$i + 1]);
+ next unless defined $k && $k ne "";
+ $fields{$k} = $v;
+ }
+}
+
+
+=head2 $t->read
+
+Reads the table into memory as instance variables
+
+=cut
+
+sub read
+{
+ my ($self) = @_;
+ my ($dat);
+
+ $self->SUPER::read or return $self;
+ init unless defined $fields{'Ascender'};
+ $self->{' INFILE'}->read($dat, 36);
+
+ TTF_Read_Fields($self, $dat, \%fields);
+ $self;
+}
+
+
+=head2 $t->out($fh)
+
+Writes the table to a file either from memory or by copying.
+
+=cut
+
+sub out
+{
+ my ($self, $fh) = @_;
+
+ return $self->SUPER::out($fh) unless $self->{' read'};
+
+ $self->{'numberOfVMetrics'} = $self->{' PARENT'}{'vmtx'}->numMetrics || $self->{'numberOfVMetrics'};
+ $fh->print(TTF_Out_Fields($self, \%fields, 36));
+ $self;
+}
+
+
+=head2 $t->update
+
+Updates various parameters in the hhea table from the hmtx table, assuming
+the C<hmtx> table is dirty.
+
+=cut
+
+sub update
+{
+ my ($self) = @_;
+ my ($vmtx) = $self->{' PARENT'}{'vmtx'};
+ my ($glyphs);
+ my ($num);
+ my ($i, $maw, $mlsb, $mrsb, $mext, $aw, $lsb, $ext);
+
+ return undef unless ($self->SUPER::update);
+ return undef unless (defined $vmtx && defined $self->{' PARENT'}{'loca'});
+ $vmtx->read->update;
+ $self->{' PARENT'}{'loca'}->read->update;
+ $glyphs = $self->{' PARENT'}{'loca'}{'glyphs'};
+ $num = $self->{' PARENT'}{'maxp'}{'numGlyphs'};
+
+ for ($i = 0; $i < $num; $i++)
+ {
+ $aw = $vmtx->{'advance'}[$i];
+ $lsb = $vmtx->{'top'}[$i];
+ if (defined $glyphs->[$i])
+ { $ext = $lsb + $glyphs->[$i]->read->{'yMax'} - $glyphs->[$i]{'yMin'}; }
+ else
+ { $ext = $aw; }
+ $maw = $aw if ($aw > $maw);
+ $mlsb = $lsb if ($lsb < $mlsb or $i == 0);
+ $mrsb = $aw - $ext if ($aw - $ext < $mrsb or $i == 0);
+ $mext = $ext if ($ext > $mext);
+ }
+ $self->{'advanceHeightMax'} = $maw;
+ $self->{'minTopSideBearing'} = $mlsb;
+ $self->{'minBottomSideBearing'} = $mrsb;
+ $self->{'yMaxExtent'} = $mext;
+ $self->{'numberOfVMetrics'} = $vmtx->numMetrics;
+ $self;
+}
+
+
+1;
+
+
+=head1 BUGS
+
+None known
+
+=head1 AUTHOR
+
+Martin Hosken Martin_Hosken at sil.org. See L<Font::TTF::Font> for copyright and
+licensing.
+
+=cut
+
Modified: packages/libfont-ttf-perl/trunk/lib/Font/TTF/Vmtx.pm
===================================================================
--- packages/libfont-ttf-perl/trunk/lib/Font/TTF/Vmtx.pm 2006-01-17 02:56:43 UTC (rev 1966)
+++ packages/libfont-ttf-perl/trunk/lib/Font/TTF/Vmtx.pm 2006-01-17 03:07:20 UTC (rev 1967)
@@ -1,86 +1,86 @@
-package Font::TTF::Vmtx;
-
-=head1 NAME
-
-Font::TTF::Vmtx - Vertical Metrics
-
-=head1 DESCRIPTION
-
-Contains the advance height and top side bearing for each glyph. Given the
-compressability of the data onto disk, this table uses information from
-other tables, and thus must do part of its output during the output of
-other tables
-
-=head1 INSTANCE VARIABLES
-
-The vertical metrics are kept in two arrays by glyph id. The variable names
-do not start with a space
-
-=over 4
-
-=item advance
-
-An array containing the advance height for each glyph
-
-=item top
-
-An array containing the top side bearing for each glyph
-
-=back
-
-=head1 METHODS
-
-=cut
-
-use strict;
-use vars qw(@ISA);
-require Font::TTF::Hmtx;
-
- at ISA = qw(Font::TTF::Hmtx);
-
-
-=head2 $t->read
-
-Reads the vertical metrics from the TTF file into memory
-
-=cut
-
-sub read
-{
- my ($self) = @_;
- my ($numh, $numg);
-
- $numh = $self->{' PARENT'}{'vhea'}->read->{'numberOfVMetrics'};
- $numg = $self->{' PARENT'}{'maxp'}->read->{'numGlyphs'};
- $self->_read($numg, $numh, "advance", "top");
-}
-
-
-=head2 $t->out($fh)
-
-Writes the metrics to a TTF file. Assumes that the C<vhea> has updated the
-numVMetrics from here
-
-=cut
-
-sub out
-{
- my ($self, $fh) = @_;
- my ($numg) = $self->{' PARENT'}{'maxp'}{'numGlyphs'};
- my ($numh) = $self->{' PARENT'}{'vhea'}{'numberOfVMetrics'};
- $self->_out($fh, $numg, $numh, "advance", "top");
-}
-
-1;
-
-=head1 BUGS
-
-None known
-
-=head1 AUTHOR
-
-Martin Hosken Martin_Hosken at sil.org. See L<Font::TTF::Font> for copyright and
-licensing.
-
-=cut
-
+package Font::TTF::Vmtx;
+
+=head1 NAME
+
+Font::TTF::Vmtx - Vertical Metrics
+
+=head1 DESCRIPTION
+
+Contains the advance height and top side bearing for each glyph. Given the
+compressability of the data onto disk, this table uses information from
+other tables, and thus must do part of its output during the output of
+other tables
+
+=head1 INSTANCE VARIABLES
+
+The vertical metrics are kept in two arrays by glyph id. The variable names
+do not start with a space
+
+=over 4
+
+=item advance
+
+An array containing the advance height for each glyph
+
+=item top
+
+An array containing the top side bearing for each glyph
+
+=back
+
+=head1 METHODS
+
+=cut
+
+use strict;
+use vars qw(@ISA);
+require Font::TTF::Hmtx;
+
+ at ISA = qw(Font::TTF::Hmtx);
+
+
+=head2 $t->read
+
+Reads the vertical metrics from the TTF file into memory
+
+=cut
+
+sub read
+{
+ my ($self) = @_;
+ my ($numh, $numg);
+
+ $numh = $self->{' PARENT'}{'vhea'}->read->{'numberOfVMetrics'};
+ $numg = $self->{' PARENT'}{'maxp'}->read->{'numGlyphs'};
+ $self->_read($numg, $numh, "advance", "top");
+}
+
+
+=head2 $t->out($fh)
+
+Writes the metrics to a TTF file. Assumes that the C<vhea> has updated the
+numVMetrics from here
+
+=cut
+
+sub out
+{
+ my ($self, $fh) = @_;
+ my ($numg) = $self->{' PARENT'}{'maxp'}{'numGlyphs'};
+ my ($numh) = $self->{' PARENT'}{'vhea'}{'numberOfVMetrics'};
+ $self->_out($fh, $numg, $numh, "advance", "top");
+}
+
+1;
+
+=head1 BUGS
+
+None known
+
+=head1 AUTHOR
+
+Martin Hosken Martin_Hosken at sil.org. See L<Font::TTF::Font> for copyright and
+licensing.
+
+=cut
+
Modified: packages/libfont-ttf-perl/trunk/lib/Font/TTF/Win32.pm
===================================================================
--- packages/libfont-ttf-perl/trunk/lib/Font/TTF/Win32.pm 2006-01-17 02:56:43 UTC (rev 1966)
+++ packages/libfont-ttf-perl/trunk/lib/Font/TTF/Win32.pm 2006-01-17 03:07:20 UTC (rev 1967)
@@ -1,33 +1,33 @@
-package Font::TTF::Win32;
-
-# use strict;
-# use vars qw($HKEY_LOCAL_MACHINE);
-
-use Win32::Registry;
-use Win32;
-use File::Spec;
-use Font::TTF::Font;
-
-
-sub findfonts
-{
- my ($sub) = @_;
- my ($font_key) = 'SOFTWARE\Microsoft\Windows' . (Win32::IsWinNT() ? ' NT' : '') . '\CurrentVersion\Fonts';
- my ($regFont, $list, $l, $font, $file);
-
-# get entry from registry for a font of this name
- $::HKEY_LOCAL_MACHINE->Open($font_key, $regFont);
- $regFont->GetValues($list);
-
- foreach $l (sort keys %{$list})
- {
- my ($fname) = $list->{$l}[0];
- next unless ($fname =~ s/\(TrueType\)$//o);
- $file = File::Spec->rel2abs($list->{$l}[2], "$ENV{'windir'}/fonts");
- $font = Font::TTF::Font->open($file) || next;
- &{$sub}($font, $fname);
- $font->release;
- }
-}
-
-1;
+package Font::TTF::Win32;
+
+# use strict;
+# use vars qw($HKEY_LOCAL_MACHINE);
+
+use Win32::Registry;
+use Win32;
+use File::Spec;
+use Font::TTF::Font;
+
+
+sub findfonts
+{
+ my ($sub) = @_;
+ my ($font_key) = 'SOFTWARE\Microsoft\Windows' . (Win32::IsWinNT() ? ' NT' : '') . '\CurrentVersion\Fonts';
+ my ($regFont, $list, $l, $font, $file);
+
+# get entry from registry for a font of this name
+ $::HKEY_LOCAL_MACHINE->Open($font_key, $regFont);
+ $regFont->GetValues($list);
+
+ foreach $l (sort keys %{$list})
+ {
+ my ($fname) = $list->{$l}[0];
+ next unless ($fname =~ s/\(TrueType\)$//o);
+ $file = File::Spec->rel2abs($list->{$l}[2], "$ENV{'windir'}/fonts");
+ $font = Font::TTF::Font->open($file) || next;
+ &{$sub}($font, $fname);
+ $font->release;
+ }
+}
+
+1;
Modified: packages/libfont-ttf-perl/trunk/lib/Font/TTF/XMLparse.pm
===================================================================
--- packages/libfont-ttf-perl/trunk/lib/Font/TTF/XMLparse.pm 2006-01-17 02:56:43 UTC (rev 1966)
+++ packages/libfont-ttf-perl/trunk/lib/Font/TTF/XMLparse.pm 2006-01-17 03:07:20 UTC (rev 1967)
@@ -1,176 +1,176 @@
-package Font::TTF::XMLparse;
-
-=head1 NAME
-
-Font::TTF::XMLparse - provides support for XML parsing. Requires Expat module XML::Parser::Expat
-
-=head1 SYNOPSIS
-
- use Font::TTF::Font;
- use Font::TTF::XMLparse;
-
- $f = Font::TTF::Font->new;
- read_xml($f, $ARGV[0]);
- $f->out($ARGV[1]);
-
-=head1 DESCRIPTION
-
-This module contains the support routines for parsing XML and generating the
-Truetype font structures as a result. The module has been separated from the rest
-of the package in order to reduce the dependency that this would bring, of the
-whole package on XML::Parser. This way, people without the XML::Parser can still
-use the rest of the package.
-
-The package interacts with another package through the use of a context containing
-and element 'receiver' which is an object which can possibly receive one of the
-following messages:
-
-=over 4
-
-=item XML_start
-
-This message is called when an open tag occurs. It is called with the context,
-tag name and the attributes. The return value has no meaning.
-
-=item XML_end
-
-This messages is called when a close tag occurs. It is called with the context,
-tag name and attributes (held over from when the tag was opened). There are 3
-possible return values from such a message:
-
-=over 8
-
-=item undef
-
-This is the default return value indicating that default processing should
-occur in which either the current element on the tree, or the text of this element
-should be stored in the parent object.
-
-=item $context
-
-This magic value marks that the element should be deleted from the parent.
-Nothing is stored in the parent. (This rather than '' is used to allow 0 returns.)
-
-=item anything
-
-Anything else is taken as the element content to be stored in the parent.
-
-=back 4
-
-=back 4
-
-In addition, the context hash passed to these messages contains the following
-keys:
-
-=over 4
-
-=item xml
-
-This is the expat xml object. The context is also available as
-$context->{'xml'}{' mycontext'}. But that is a long winded way of not saying much!
-
-=item font
-
-This is the base object that was passed in for XML parsing.
-
-=item receiver
-
-This holds the current receiver of parsing events. It may be set in associated
-application to adjust which objects should receive messages when. It is also stored
-in the parsing stack to ensure that where an object changes it during XML_start, that
-that same object that received XML_start will receive the corresponding XML_end
-
-=item stack
-
-This is the parsing stack, used internally to hold the current receiver and attributes
-for each element open, as a complete hierarchy back to the root element.
-
-=item tree
-
-This element contains the storage tree corresponding to the parent of each element
-in the stack. The default action is to push undef onto this stack during XML_start
-and then to resolve this, either in the associated application (by changing
-$context->{'tree'}[-1]) or during XML_end of a child element, by which time we know
-whether we are dealing with an array or a hash or what.
-
-=item text
-
-Character processing is to insert all the characters into the text element of the
-context for available use later.
-
-=back 4
-
-=head1 METHODS
-
-=cut
-
-use XML::Parser::Expat;
-use Exporter;
-
-use strict;
-use vars qw(@ISA @EXPORT);
-
- at ISA = qw(Exporter);
- at EXPORT = qw(read_xml);
-
-sub read_xml
-{
- my ($font, $fname) = @_;
-
- my ($xml) = XML::Parser::Expat->new;
- my ($context) = {'xml' => $xml, 'font' => $font};
-
- $xml->setHandlers('Start' => sub {
- my ($x, $tag, %attrs) = @_;
- my ($context) = $x->{' mycontext'};
- my ($fn) = $context->{'receiver'}->can('XML_start');
-
- push(@{$context->{'tree'}}, undef);
- push(@{$context->{'stack'}}, [$context->{'receiver'}, {%attrs}]);
- &{$fn}($context->{'receiver'}, $context, $tag, %attrs) if defined $fn;
- },
- 'End' => sub {
- my ($x, $tag) = @_;
- my ($context) = $x->{' mycontext'};
- my ($fn) = $context->{'receiver'}->can('XML_end');
- my ($stackinfo) = pop(@{$context->{'stack'}});
- my ($current, $res);
-
- $context->{'receiver'} = $stackinfo->[0];
- $context->{'text'} =~ s/^\s*(.*?)\s*$/$1/o;
- $res = &{$fn}($context->{'receiver'}, $context, $tag, %{$stackinfo->[1]}) if defined $fn;
- $current = pop(@{$context->{'tree'}});
- $current = $context->{'text'} unless (defined $current);
- $context->{'text'} = '';
-
- if (defined $res)
- {
- return if ($res eq $context);
- $current = $res;
- }
- return unless $#{$context->{'tree'}} >= 0;
- if ($tag eq 'elem')
- {
- $context->{'tree'}[-1] = [] unless defined $context->{'tree'}[-1];
- push (@{$context->{'tree'}[-1]}, $current);
- } else
- {
- $context->{'tree'}[-1] = {} unless defined $context->{'tree'}[-1];
- $context->{'tree'}[-1]{$tag} = $current;
- }
- },
- 'Char' => sub {
- my ($x, $str) = @_;
- $x->{' mycontext'}{'text'} .= $str;
- });
-
- $xml->{' mycontext'} = $context;
-
- $context->{'receiver'} = $font;
- if (ref $fname)
- { return $xml->parse($fname); }
- else
- { return $xml->parsefile($fname); }
-}
-
-
+package Font::TTF::XMLparse;
+
+=head1 NAME
+
+Font::TTF::XMLparse - provides support for XML parsing. Requires Expat module XML::Parser::Expat
+
+=head1 SYNOPSIS
+
+ use Font::TTF::Font;
+ use Font::TTF::XMLparse;
+
+ $f = Font::TTF::Font->new;
+ read_xml($f, $ARGV[0]);
+ $f->out($ARGV[1]);
+
+=head1 DESCRIPTION
+
+This module contains the support routines for parsing XML and generating the
+Truetype font structures as a result. The module has been separated from the rest
+of the package in order to reduce the dependency that this would bring, of the
+whole package on XML::Parser. This way, people without the XML::Parser can still
+use the rest of the package.
+
+The package interacts with another package through the use of a context containing
+and element 'receiver' which is an object which can possibly receive one of the
+following messages:
+
+=over 4
+
+=item XML_start
+
+This message is called when an open tag occurs. It is called with the context,
+tag name and the attributes. The return value has no meaning.
+
+=item XML_end
+
+This messages is called when a close tag occurs. It is called with the context,
+tag name and attributes (held over from when the tag was opened). There are 3
+possible return values from such a message:
+
+=over 8
+
+=item undef
+
+This is the default return value indicating that default processing should
+occur in which either the current element on the tree, or the text of this element
+should be stored in the parent object.
+
+=item $context
+
+This magic value marks that the element should be deleted from the parent.
+Nothing is stored in the parent. (This rather than '' is used to allow 0 returns.)
+
+=item anything
+
+Anything else is taken as the element content to be stored in the parent.
+
+=back 4
+
+=back 4
+
+In addition, the context hash passed to these messages contains the following
+keys:
+
+=over 4
+
+=item xml
+
+This is the expat xml object. The context is also available as
+$context->{'xml'}{' mycontext'}. But that is a long winded way of not saying much!
+
+=item font
+
+This is the base object that was passed in for XML parsing.
+
+=item receiver
+
+This holds the current receiver of parsing events. It may be set in associated
+application to adjust which objects should receive messages when. It is also stored
+in the parsing stack to ensure that where an object changes it during XML_start, that
+that same object that received XML_start will receive the corresponding XML_end
+
+=item stack
+
+This is the parsing stack, used internally to hold the current receiver and attributes
+for each element open, as a complete hierarchy back to the root element.
+
+=item tree
+
+This element contains the storage tree corresponding to the parent of each element
+in the stack. The default action is to push undef onto this stack during XML_start
+and then to resolve this, either in the associated application (by changing
+$context->{'tree'}[-1]) or during XML_end of a child element, by which time we know
+whether we are dealing with an array or a hash or what.
+
+=item text
+
+Character processing is to insert all the characters into the text element of the
+context for available use later.
+
+=back 4
+
+=head1 METHODS
+
+=cut
+
+use XML::Parser::Expat;
+use Exporter;
+
+use strict;
+use vars qw(@ISA @EXPORT);
+
+ at ISA = qw(Exporter);
+ at EXPORT = qw(read_xml);
+
+sub read_xml
+{
+ my ($font, $fname) = @_;
+
+ my ($xml) = XML::Parser::Expat->new;
+ my ($context) = {'xml' => $xml, 'font' => $font};
+
+ $xml->setHandlers('Start' => sub {
+ my ($x, $tag, %attrs) = @_;
+ my ($context) = $x->{' mycontext'};
+ my ($fn) = $context->{'receiver'}->can('XML_start');
+
+ push(@{$context->{'tree'}}, undef);
+ push(@{$context->{'stack'}}, [$context->{'receiver'}, {%attrs}]);
+ &{$fn}($context->{'receiver'}, $context, $tag, %attrs) if defined $fn;
+ },
+ 'End' => sub {
+ my ($x, $tag) = @_;
+ my ($context) = $x->{' mycontext'};
+ my ($fn) = $context->{'receiver'}->can('XML_end');
+ my ($stackinfo) = pop(@{$context->{'stack'}});
+ my ($current, $res);
+
+ $context->{'receiver'} = $stackinfo->[0];
+ $context->{'text'} =~ s/^\s*(.*?)\s*$/$1/o;
+ $res = &{$fn}($context->{'receiver'}, $context, $tag, %{$stackinfo->[1]}) if defined $fn;
+ $current = pop(@{$context->{'tree'}});
+ $current = $context->{'text'} unless (defined $current);
+ $context->{'text'} = '';
+
+ if (defined $res)
+ {
+ return if ($res eq $context);
+ $current = $res;
+ }
+ return unless $#{$context->{'tree'}} >= 0;
+ if ($tag eq 'elem')
+ {
+ $context->{'tree'}[-1] = [] unless defined $context->{'tree'}[-1];
+ push (@{$context->{'tree'}[-1]}, $current);
+ } else
+ {
+ $context->{'tree'}[-1] = {} unless defined $context->{'tree'}[-1];
+ $context->{'tree'}[-1]{$tag} = $current;
+ }
+ },
+ 'Char' => sub {
+ my ($x, $str) = @_;
+ $x->{' mycontext'}{'text'} .= $str;
+ });
+
+ $xml->{' mycontext'} = $context;
+
+ $context->{'receiver'} = $font;
+ if (ref $fname)
+ { return $xml->parse($fname); }
+ else
+ { return $xml->parsefile($fname); }
+}
+
+
Modified: packages/libfont-ttf-perl/trunk/lib/ttfmod.pl
===================================================================
--- packages/libfont-ttf-perl/trunk/lib/ttfmod.pl 2006-01-17 02:56:43 UTC (rev 1966)
+++ packages/libfont-ttf-perl/trunk/lib/ttfmod.pl 2006-01-17 03:07:20 UTC (rev 1967)
@@ -1,174 +1,174 @@
-# Title: TTFMOD.PL
-# Author: M. Hosken
-# Description: Read TTF file calling user functions for each table
-# and output transformed tables to new TTF file.
-# Useage: TTFMOD provides the complete control loop for processing
-# the TTF files. All that the caller need supply is an
-# associative array of functions to call keyed by the TTF
-# table name and the two filenames.
-#
-# &ttfmod($infile, $outfile, *fns [, @must]);
-#
-# *fns is an associative array keyed by table name with
-# values of the name of the subroutine in package main to
-# be called to transfer the table from INFILE to OUTFILE.
-# The subroutine is called with the following parameters and
-# expected return values:
-#
-# ($len, $csum) = &sub(*INFILE, *OUTFILE, $len);
-#
-# INFILE and OUTFILE are the input and output streams, $len
-# is the length of the table according to the directory.
-# The return values are $len = new length of table to be
-# given in the table directory. $csum = new value of table
-# checksum. A way to test that this is correct is to
-# checksum the whole file (e.g. using CSUM.BAT) and to
-# ensure that the value is 0xB1B0AFBA according to a 32 bit
-# checksum calculated bigendien.
-#
-# @must consists of a list of tables which must exist in the
-# final output file, either by being there alread or by being
-# inserted.
-#
-# Modifications:
-# MJPH 1.00 22-SEP-1994 Original
-# MJPH 1.1 18-MAR-1998 Added @must to ttfmod()
-# MJPH 1.1.1 25-MAR-1998 Added $csum to copytab (to make reusable)
-
-package ttfmod;
-
-sub main'ttfmod {
- local($infile, $outfile, *fns, @must) = @_;
-
- # open files as binary. Notice OUTFILE is opened for update not just write
- open(INFILE, "$infile") || die "Unable top open \"$infile\" for reading";
- binmode INFILE;
- open(OUTFILE, "+>$outfile") || die "Unable to open \"$outfile\" for writing";
- binmode OUTFILE;
-
- seek(INFILE, 0, 0);
- read(INFILE, $dir_head, 12) || die "Reading table header";
- ($dir_num) = unpack("x4n", $dir_head);
- print OUTFILE $dir_head;
- # read and unpack table directory
- for ($i = 0; $i < $dir_num; $i++)
- {
- read(INFILE, $dir_val, 16) || die "Reading table entry";
- $dir{unpack("a4", $dir_val)} = join(":", $i, unpack("x4NNN", $dir_val));
- print OUTFILE $dir_val;
- printf STDERR "%s %08x\n", unpack("a4", $dir_val), unpack("x8N", $dir_val)
- if (defined $main'opt_z);
- }
- foreach $n (@must)
- {
- next if defined $dir{$n};
- $dir{$n} = "$i:0:-1:0";
- $i++; $dir_num++;
- print OUTFILE pack("a4NNN", $n, 0, -1, 0);
- }
- substr($dir_head, 4, 2) = pack("n", $dir_num);
- $csum = unpack("%32N*", $dir_head);
- $off = tell(OUTFILE);
- seek(OUTFILE, 0, 0);
- print OUTFILE $dir_head;
- seek (OUTFILE, $off, 0);
- # process tables in order they occur in the file
- @dirlist = sort byoffset keys(%dir);
- foreach $tab (@dirlist)
- {
- @tab_split = split(':', $dir{$tab});
- seek(INFILE, $tab_split[2], 0); # offset
- $tab_split[2] = tell(OUTFILE);
- if (defined $fns{$tab})
- {
- $temp = "main'$fns{$tab}";
- ($dir_len, $sum) = &$temp(*INFILE, *OUTFILE, $tab_split[3]);
- }
- else
- {
- ($dir_len, $sum) = ©tab(*INFILE, *OUTFILE, $tab_split[3]);
- }
- $tab_split[3] = $dir_len; # len
- $tab_split[1] = $sum; # checksum
- $out_dir{$tab} = join(":", @tab_split);
- }
- # now output directory in same order as original directory
- @dirlist = sort byindex keys(%out_dir);
- foreach $tab (@dirlist)
- {
- @tab_split = split(':', $out_dir{$tab});
- seek (OUTFILE, 12 + $tab_split[0] * 16, 0); # directory index
- print OUTFILE pack("A4N3", $tab, @tab_split[1..3]);
- foreach $i (1..3, 1) # checksum directory values with csum twice
- {
- $csum += $tab_split[$i];
- # this line ensures $csum stays within 32 bit bounds, clipping as necessary
- if ($csum > 0xffffffff) { $csum -= 0xffffffff; $csum--; }
- }
- # checksum the tag
- $csum += unpack("N", $tab);
- if ($csum > 0xffffffff) { $csum -= 0xffffffff; $csum--; }
- }
- # handle main checksum
- @tab_split = split(':', $out_dir{"head"});
- seek(OUTFILE, $tab_split[2], 0);
- read(OUTFILE, $head_head, 12); # read first bit of "head" table
- @head_split = unpack("N3", $head_head);
- $tab_split[1] -= $head_split[2]; # subtract old checksum
- $csum -= $head_split[2] * 2; # twice because had double effect
- # already
- if ($csum < 0 ) { $csum += 0xffffffff; $csum++; }
- $head_split[2] = 0xB1B0AFBA - $csum; # calculate new checksum
- seek (OUTFILE, 12 + $tab_split[0] * 16, 0);
- print OUTFILE pack("A4N3", "head", @tab_split[1..3]);
- seek (OUTFILE, $tab_split[2], 0); # rewrite first bit of "head" table
- print OUTFILE pack("N3", @head_split);
-
- # finish up
- close(OUTFILE);
- close(INFILE);
- }
-
-# support function for sorting by table offset
-sub byoffset {
- @t1 = split(':', $dir{$a});
- @t2 = split(':', $dir{$b});
- return 1 if ($t1[2] == -1); # put inserted tables at the end
- return -1 if ($t2[2] == -1);
- return $t1[2] <=> $t2[2];
- }
-
-# support function for sorting by directory entry order
-sub byindex {
- $t1 = split(':', $dir{$a}, 1);
- $t2 = split(':', $dir{$b}, 1);
- return $t1 <=> $t2;
- }
-
-# default table action: copies a table from input to output, recalculating
-# the checksum (just to be absolutely sure).
-sub copytab {
- local(*INFILE, *OUTFILE, $len, $csum) = @_;
-
- while ($len > 0)
- {
- $count = ($len > 8192) ? 8192 : $len; # 8K buffering
- read(INFILE, $buf, $count) == $count || die "Copying";
- $buf .= "\0" x (4 - ($count & 3)) if ($count & 3); # pad to long
- print OUTFILE $buf;
- $csum += unpack("%32N*", $buf);
- if ($csum > 0xffffffff) { $csum -= 0xffffffff; $csum--; }
- $len -= $count;
- }
- ($_[2], $csum);
- }
-
-# test routine to copy file from input to output, no changes
-package main;
-
-if ($test_package)
- {
- &ttfmod($ARGV[0], $ARGV[1], *dummy);
- }
-else
- { 1; }
+# Title: TTFMOD.PL
+# Author: M. Hosken
+# Description: Read TTF file calling user functions for each table
+# and output transformed tables to new TTF file.
+# Useage: TTFMOD provides the complete control loop for processing
+# the TTF files. All that the caller need supply is an
+# associative array of functions to call keyed by the TTF
+# table name and the two filenames.
+#
+# &ttfmod($infile, $outfile, *fns [, @must]);
+#
+# *fns is an associative array keyed by table name with
+# values of the name of the subroutine in package main to
+# be called to transfer the table from INFILE to OUTFILE.
+# The subroutine is called with the following parameters and
+# expected return values:
+#
+# ($len, $csum) = &sub(*INFILE, *OUTFILE, $len);
+#
+# INFILE and OUTFILE are the input and output streams, $len
+# is the length of the table according to the directory.
+# The return values are $len = new length of table to be
+# given in the table directory. $csum = new value of table
+# checksum. A way to test that this is correct is to
+# checksum the whole file (e.g. using CSUM.BAT) and to
+# ensure that the value is 0xB1B0AFBA according to a 32 bit
+# checksum calculated bigendien.
+#
+# @must consists of a list of tables which must exist in the
+# final output file, either by being there alread or by being
+# inserted.
+#
+# Modifications:
+# MJPH 1.00 22-SEP-1994 Original
+# MJPH 1.1 18-MAR-1998 Added @must to ttfmod()
+# MJPH 1.1.1 25-MAR-1998 Added $csum to copytab (to make reusable)
+
+package ttfmod;
+
+sub main'ttfmod {
+ local($infile, $outfile, *fns, @must) = @_;
+
+ # open files as binary. Notice OUTFILE is opened for update not just write
+ open(INFILE, "$infile") || die "Unable top open \"$infile\" for reading";
+ binmode INFILE;
+ open(OUTFILE, "+>$outfile") || die "Unable to open \"$outfile\" for writing";
+ binmode OUTFILE;
+
+ seek(INFILE, 0, 0);
+ read(INFILE, $dir_head, 12) || die "Reading table header";
+ ($dir_num) = unpack("x4n", $dir_head);
+ print OUTFILE $dir_head;
+ # read and unpack table directory
+ for ($i = 0; $i < $dir_num; $i++)
+ {
+ read(INFILE, $dir_val, 16) || die "Reading table entry";
+ $dir{unpack("a4", $dir_val)} = join(":", $i, unpack("x4NNN", $dir_val));
+ print OUTFILE $dir_val;
+ printf STDERR "%s %08x\n", unpack("a4", $dir_val), unpack("x8N", $dir_val)
+ if (defined $main'opt_z);
+ }
+ foreach $n (@must)
+ {
+ next if defined $dir{$n};
+ $dir{$n} = "$i:0:-1:0";
+ $i++; $dir_num++;
+ print OUTFILE pack("a4NNN", $n, 0, -1, 0);
+ }
+ substr($dir_head, 4, 2) = pack("n", $dir_num);
+ $csum = unpack("%32N*", $dir_head);
+ $off = tell(OUTFILE);
+ seek(OUTFILE, 0, 0);
+ print OUTFILE $dir_head;
+ seek (OUTFILE, $off, 0);
+ # process tables in order they occur in the file
+ @dirlist = sort byoffset keys(%dir);
+ foreach $tab (@dirlist)
+ {
+ @tab_split = split(':', $dir{$tab});
+ seek(INFILE, $tab_split[2], 0); # offset
+ $tab_split[2] = tell(OUTFILE);
+ if (defined $fns{$tab})
+ {
+ $temp = "main'$fns{$tab}";
+ ($dir_len, $sum) = &$temp(*INFILE, *OUTFILE, $tab_split[3]);
+ }
+ else
+ {
+ ($dir_len, $sum) = ©tab(*INFILE, *OUTFILE, $tab_split[3]);
+ }
+ $tab_split[3] = $dir_len; # len
+ $tab_split[1] = $sum; # checksum
+ $out_dir{$tab} = join(":", @tab_split);
+ }
+ # now output directory in same order as original directory
+ @dirlist = sort byindex keys(%out_dir);
+ foreach $tab (@dirlist)
+ {
+ @tab_split = split(':', $out_dir{$tab});
+ seek (OUTFILE, 12 + $tab_split[0] * 16, 0); # directory index
+ print OUTFILE pack("A4N3", $tab, @tab_split[1..3]);
+ foreach $i (1..3, 1) # checksum directory values with csum twice
+ {
+ $csum += $tab_split[$i];
+ # this line ensures $csum stays within 32 bit bounds, clipping as necessary
+ if ($csum > 0xffffffff) { $csum -= 0xffffffff; $csum--; }
+ }
+ # checksum the tag
+ $csum += unpack("N", $tab);
+ if ($csum > 0xffffffff) { $csum -= 0xffffffff; $csum--; }
+ }
+ # handle main checksum
+ @tab_split = split(':', $out_dir{"head"});
+ seek(OUTFILE, $tab_split[2], 0);
+ read(OUTFILE, $head_head, 12); # read first bit of "head" table
+ @head_split = unpack("N3", $head_head);
+ $tab_split[1] -= $head_split[2]; # subtract old checksum
+ $csum -= $head_split[2] * 2; # twice because had double effect
+ # already
+ if ($csum < 0 ) { $csum += 0xffffffff; $csum++; }
+ $head_split[2] = 0xB1B0AFBA - $csum; # calculate new checksum
+ seek (OUTFILE, 12 + $tab_split[0] * 16, 0);
+ print OUTFILE pack("A4N3", "head", @tab_split[1..3]);
+ seek (OUTFILE, $tab_split[2], 0); # rewrite first bit of "head" table
+ print OUTFILE pack("N3", @head_split);
+
+ # finish up
+ close(OUTFILE);
+ close(INFILE);
+ }
+
+# support function for sorting by table offset
+sub byoffset {
+ @t1 = split(':', $dir{$a});
+ @t2 = split(':', $dir{$b});
+ return 1 if ($t1[2] == -1); # put inserted tables at the end
+ return -1 if ($t2[2] == -1);
+ return $t1[2] <=> $t2[2];
+ }
+
+# support function for sorting by directory entry order
+sub byindex {
+ $t1 = split(':', $dir{$a}, 1);
+ $t2 = split(':', $dir{$b}, 1);
+ return $t1 <=> $t2;
+ }
+
+# default table action: copies a table from input to output, recalculating
+# the checksum (just to be absolutely sure).
+sub copytab {
+ local(*INFILE, *OUTFILE, $len, $csum) = @_;
+
+ while ($len > 0)
+ {
+ $count = ($len > 8192) ? 8192 : $len; # 8K buffering
+ read(INFILE, $buf, $count) == $count || die "Copying";
+ $buf .= "\0" x (4 - ($count & 3)) if ($count & 3); # pad to long
+ print OUTFILE $buf;
+ $csum += unpack("%32N*", $buf);
+ if ($csum > 0xffffffff) { $csum -= 0xffffffff; $csum--; }
+ $len -= $count;
+ }
+ ($_[2], $csum);
+ }
+
+# test routine to copy file from input to output, no changes
+package main;
+
+if ($test_package)
+ {
+ &ttfmod($ARGV[0], $ARGV[1], *dummy);
+ }
+else
+ { 1; }
More information about the Pkg-perl-cvs-commits
mailing list