<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">package Font::TTF::Delta;

=head1 NAME 

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-&gt;read($dat, 6);
    ($self-&gt;{'first'}, $self-&gt;{'last'}, $fmt) = TTF_Unpack("S3", $dat);
    $self-&gt;{'fmt'} = $fmt;

    $fmt = 1 &lt;&lt; $fmt;
    $num = ((($self-&gt;{'last'} - $self-&gt;{'first'} + 1) * $fmt) + 15) &gt;&gt; 8;
    $fh-&gt;read($dat, $num);

    $mask = (0xffff &lt;&lt; (16 - $fmt)) &amp; 0xffff;
    $j = 0;
    for ($i = $self-&gt;{'first'}; $i &lt;= $self-&gt;{'last'}; $i++)
    {
        if ($j == 0)
        {
            $num = TTF_Unpack("S", substr($dat, 0, 2));
            substr($dat, 0, 2) = '';
        }
        push (@{$self-&gt;{'val'}}, ($num &amp; $mask) &gt;&gt; (16 - $fmt));
        $num &lt;&lt;= $fmt;
        $j += $fmt;
        $j = 0 if ($j &gt;= 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-&gt;{'val'}})
    {
        my ($tfmt) = $f &gt; 0 ? $f + 1 : -$f;
        $fmt = $tfmt if $tfmt &gt; $fmt;
    }

    if ($fmt &gt; 8)
    { $fmt = 3; }
    elsif ($fmt &gt; 2)
    { $fmt = 2; }
    else
    { $fmt = 1; }

    $out = TTF_Pack("S3", $self-&gt;{'first'}, $self-&gt;{'last'}, $fmt);

    $fmt = 1 &lt;&lt; $fmt;
    $mask = 0xffff &gt;&gt; (16 - $fmt);
    $j = 0; $dat = 0;
    foreach $f (@{$self-&gt;{'val'}})
    {
        $dat |= ($f &amp; $mask) &lt;&lt; (16 - $fmt - $j);
        $j += $fmt;
        if ($j &gt;= 16)
        {
            $j = 0;
            $out .= TTF_Pack("S", $dat);
            $dat = 0;
        }
    }
    $out .= pack('n', $dat) if ($j &gt; 0);
    $fh-&gt;print($out) unless $style;
    $out;
}

=head2 $d-&gt;signature()

Returns a content based identifying string for this delta for
compression purposes

=cut

sub signature
{
    my ($self) = @_;
    return join (",", $self-&gt;{'first'}, $self-&gt;{'last'}, @{$self-&gt;{'val'}});
}


=head2 $d-&gt;out_xml($context)

Outputs a delta in XML

=cut

sub out_xml
{
    my ($self, $context, $depth) = @_;
    my ($fh) = $context-&gt;{'fh'};

    $fh-&gt;printf("%s&lt;delta first='%s' last='%s'&gt;\n", $depth, $self-&gt;{'first'}, $self-&gt;{'last'});
    $fh-&gt;print("$depth$context-&gt;{'indent'}" . join (' ', @{$self-&gt;{'val'}}) . "\n") if defined ($self-&gt;{'val'});
    $fh-&gt;print("$depth&lt;/delta&gt;\n");
}

=head1 AUTHOR

Martin Hosken Martin_Hosken@sil.org. See L&lt;Font::TTF::Font&gt; for copyright and
licensing.

=cut

1;

</pre></body></html>