<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">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;

@ISA = qw(Font::TTF::Table);

=head2 $t-&gt;read

Reads the features from the TTF file into memory

=cut

sub read
{
    my ($self) = @_;
    my ($featureCount, $features);

    $self-&gt;SUPER::read_dat or return $self;

    ($self-&gt;{'version'}, $featureCount) = TTF_Unpack("vS", $self-&gt;{' dat'});

    $features = [];
    foreach (1 .. $featureCount) {
        my ($feature, $nSettings, $settingTable, $featureFlags, $nameIndex)
                = TTF_Unpack("SSLSS", substr($self-&gt;{' dat'}, $_ * 12, 12));
        push @$features,
            {
                'feature'    =&gt; $feature,
                'name'        =&gt; $nameIndex,
                'exclusive'    =&gt; (($featureFlags &amp; 0x8000) != 0),
                'settings'    =&gt; { TTF_Unpack("S*", substr($self-&gt;{' dat'}, $settingTable, $nSettings * 4)) }
            };
    }
    $self-&gt;{'features'} = $features;
    
    delete $self-&gt;{' dat'}; # no longer needed, and may become obsolete
    
    $self;
}

=head2 $t-&gt;out($fh)

Writes the features to a TTF file

=cut

sub out
{
    my ($self, $fh) = @_;
    my ($features, $numFeatures, $settings, $featuresData, $settingsData);
    
    return $self-&gt;SUPER::out($fh) unless $self-&gt;{' read'};

    $features = $self-&gt;{'features'};
    $numFeatures = @$features;

    foreach (@$features) {
        $settings = $_-&gt;{'settings'};
        $featuresData .= TTF_Pack("SSLSS",
                                    $_-&gt;{'feature'},
                                    scalar keys %$settings,
                                    12 + 12 * $numFeatures + length $settingsData,
                                    ($_-&gt;{'exclusive'} ? 0x8000 : 0x0000),
                                    $_-&gt;{'name'});
        foreach (sort {$a &lt;=&gt; $b} keys %$settings) {
            $settingsData .= TTF_Pack("SS", $_, $settings-&gt;{$_});
        }
    }

    $fh-&gt;print(TTF_Pack("vSSL", $self-&gt;{'version'}, $numFeatures, 0, 0));
    $fh-&gt;print($featuresData);
    $fh-&gt;print($settingsData);

    $self;
}

=head2 $t-&gt;print($fh)

Prints a human-readable representation of the table

=cut

sub print
{
    my ($self, $fh) = @_;
    my ($names, $features, $settings);

    $self-&gt;read;

    $names = $self-&gt;{' PARENT'}-&gt;{'name'};
    $names-&gt;read;

    $fh = 'STDOUT' unless defined $fh;

    $features = $self-&gt;{'features'};
    foreach (@$features) {
        $fh-&gt;printf("Feature %d, %s, name %d # '%s'\n",
                    $_-&gt;{'feature'},
                    ($_-&gt;{'exclusive'} ? "exclusive" : "additive"),
                    $_-&gt;{'name'},
                    $names-&gt;{'strings'}[$_-&gt;{'name'}][1][0]{0});
        $settings = $_-&gt;{'settings'};
        foreach (sort { $a &lt;=&gt; $b } keys %$settings) {
            $fh-&gt;printf("\tSetting %d, name %d # '%s'\n",
                        $_, $settings-&gt;{$_}, $names-&gt;{'strings'}[$settings-&gt;{$_}][1][0]{0});
        }
    }
    
    $self;
}

sub settingName
{
    my ($self, $feature, $setting) = @_;

    $self-&gt;read;

    my $names = $self-&gt;{' PARENT'}-&gt;{'name'};
    $names-&gt;read;
    
    my $features = $self-&gt;{'features'};
    my ($featureEntry) = grep { $_-&gt;{'feature'} == $feature } @$features;
    my $featureName = $names-&gt;{'strings'}[$featureEntry-&gt;{'name'}][1][0]{0};
    my $settingName = $featureEntry-&gt;{'exclusive'}
            ? $names-&gt;{'strings'}[$featureEntry-&gt;{'settings'}-&gt;{$setting}][1][0]{0}
            : $names-&gt;{'strings'}[$featureEntry-&gt;{'settings'}-&gt;{$setting &amp; ~1}][1][0]{0}
                . (($setting &amp; 1) == 0 ? " On" : " Off");

    ($featureName, $settingName);
}

1;

=head1 BUGS

None known

=head1 AUTHOR

Jonathan Kew L&lt;Jonathan_Kew@sil.org&gt;. See L&lt;Font::TTF::Font&gt; for copyright and
licensing.

=cut

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