--- /dev/null
+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;
+