Introduce src dir.
[librarian.git] / src / librarian / font-optimizer / ext / Font-TTF / lib / Font / TTF / GDEF.pm
diff --git a/src/librarian/font-optimizer/ext/Font-TTF/lib/Font/TTF/GDEF.pm b/src/librarian/font-optimizer/ext/Font-TTF/lib/Font/TTF/GDEF.pm
new file mode 100644 (file)
index 0000000..9519ee8
--- /dev/null
@@ -0,0 +1,313 @@
+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);
+
+@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();
+    if ($new_gdef)
+    {
+        $fh->read($dat, 12);
+        ($self->{'Version'}, $goff, $aoff, $loff, $moff) = TTF_Unpack('fS4', $dat);
+    }
+    else
+    {
+        $fh->read($dat, 10);
+        ($self->{'Version'}, $goff, $aoff, $loff) = TTF_Unpack('fS3', $dat);
+    }
+
+    if ($goff > 0)
+    {
+        $fh->seek($goff + $boff, 0);
+        $self->{'GLYPH'} = Font::TTF::Coverage->new(0)->read($fh);
+    }
+
+    if ($new_gdef && $moff > 0 && $moff < $self->{' LENGTH'})
+    {
+        $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),
+                        $#{$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;
+