|
Packit |
5d935b |
package Font::TTF::Silf;
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=head1 NAME
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
Font::TTF::Silf - The main Graphite table
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=head1 DESCRIPTION
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
The Silf table holds the core of the Graphite rules for a font. A Silf table has
|
|
Packit |
5d935b |
potentially multiple silf subtables, although there is usually only one. Within a silf subtable,
|
|
Packit |
5d935b |
there are a number of passes which contain the actual finite state machines to match rules
|
|
Packit |
5d935b |
and the constraint and action code to be executed when a rule matches.
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=head1 INSTANCE VARIABLES
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=over 4
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=item Version
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
Silf table format version
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=item Compiler
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
Lowest compiler version necessary to fully support the semantics expressed in this
|
|
Packit |
5d935b |
Graphite description
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=item SILF
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
An array of Silf subtables
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=over 4
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=item maxGlyphID
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
The maximum glyph id referenced including pseudo and non glyphs
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=item Ascent
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
Extra ascent to be added to the font ascent.
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=item Descent
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
Extra descent to be added to the font descent. Both values are assumed to be
|
|
Packit |
5d935b |
positive for a descender below the base line.
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=item substPass
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
Pass index into PASS of the first substitution pass.
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=item posPass
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
Pass index into PASS of the first positioning pass.
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=item justPass
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
Pass index into PASS of the first justification pass.
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=item bidiPass
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
Pass index of the pass before which the bidirectional processing pass will be executed.
|
|
Packit |
5d935b |
0xFF indicates that there is no bidi pass to be executed.
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=item Flags
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
A bitfield of flags:
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
0 - Indicates there are line end contextual rules in one of the passes
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=item maxPreContext
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
Maximum length of a context preceding a cross line boundary contextualisation.
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=item maxPostContext
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
Maximum length of a context following a cross line boundary contextualsation.
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=item attrPseudo
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
Glyph attribute for the actual glyph id associated with a pseudo glyph.
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=item attrBreakWeight
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
Glyph attribute number of the attribute holding the default breakweight associated with a glyph.
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=item attrDirectionality
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
Glyph attribute number of the attribute holding the default directionality value associated with a glyph.
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=item JUST
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
The may be a number of justification levels each with their own property values.
|
|
Packit |
5d935b |
This points to an array of hashes, one for each justification level.
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=over 4
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=item attrStretch
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
Glyph attribute number for the amount of stretch allowed before this glyph.
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=item attrShrink
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
Glyph attribute number for the amount of shrink allowed before this glyph.
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=item attrStep
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
Glyph attribute number specifying the minimum granularity of actual spacing associated with this glyph at this level.
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=item attrWeight
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
Glyph attribute number giving the weight associated with spreading space across a run of glyphs.
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=item runto
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
Which level starts the next stage.
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=back
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=item numLigComp
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
Number of initial glyph attributes that represent ligature components
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=item numUserAttr
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
Number of user defined slot attributes referenced. Tells the engine how much space to
|
|
Packit |
5d935b |
allocate to a slot for user attributes.
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=item maxCompPerLig
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
Maximum number of components per ligature.
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=item direction
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
Supported directions for this writing system
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=item CRIT_FEATURE
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
Array of critical features.
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=item scripts
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
Array of script tags that indicate which set of GDL rules to execute if there is more than one in a font.
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=item lbGID
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
Glyph ID of the linebreak pseudo glyph.
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=item pseudos
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
Hash of Unicode values to pseduo glyph ids.
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=item classes
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
This is an array of classes, each of which is an array of glyph ids in class order.
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=item PASS
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
The details of rules and actions are stored in passes. This value is an array of pass subobjects one for each pass.
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=over 4
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=item flags
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
This is a bitfield:
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
0 - If true, this pass makes no change to the slot stream considered as a sequence of glyph ids.
|
|
Packit |
5d935b |
Only slot attributes are expected to change (for example during positioning).
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=item maxRuleLoop
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
How many times the engine will allow rules to be tested and run without the engine advancing through the
|
|
Packit |
5d935b |
input slot stream.
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=item maxRuleContext
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
Number of slots of input needed to run this pass.
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=item maxBackup
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
Number of slots by which the following pass needs to trail this pass (i.e. the maximum this pass is allowed to back up).
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=item numRules
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
Number of action code blocks, and so uncompressed rules, in this pass.
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=item numRows
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
Number of rows in the finite state machine.
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=item numTransitional
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
Number of rows in the finite state machine that are not final states. This specifies the number of rows in the fsm
|
|
Packit |
5d935b |
element.
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=item numSuccess
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
Number of success states. A success state may also be a transitional state.
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=item numColumns
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
Number of columns in the finite state machine.
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=item colmap
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
A hash, indexed by glyphid, that gives the fsm column number associated with that glyphid. If not present, then
|
|
Packit |
5d935b |
the glyphid is not part of the fsm and will finish fsm processing if it occurs.
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=item rulemap
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
An array of arrays, one for each success state. Each array holds a list of rule numbers associated with that state.
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=item minRulePreContext
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
Minimum number of items in a rule's precontext.
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=item maxRulePreContext
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
The maximum number of items in any rule's precontext.
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=item startStates
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
Array of starting state numbers dependeing on the length of actual precontext.
|
|
Packit |
5d935b |
There are maxRulePreContext - minRulePreContext + 1 of these.
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=item ruleSortKeys
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
An array of sort keys one for each rule giving the length of the rule including its precontext.
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=item rulePreContexts
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
An array of precontext lengths for each rule.
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=item fsm
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
A two dimensional array such that $p->{'fsm'}[$row][$col] gives the row of the next node to try in the fsm.
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=item passConstraintLen
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
Length in bytes of the passConstraint code.
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=item passConstraintCode
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
A byte string holding the pass constraint code.
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=item constraintCode
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
An array of byte strings holding the constraint code for each rule.
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=item actionCode
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
An array of byte strings holding the action code for each rule.
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=back
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=back
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=back
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=cut
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
use Font::TTF::Table;
|
|
Packit |
5d935b |
use Font::TTF::Utils;
|
|
Packit |
5d935b |
use strict;
|
|
Packit |
5d935b |
use vars qw(@ISA);
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
@ISA = qw(Font::TTF::Table);
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=head2 @opcodes
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
Each array holds the name of the opcode, the number of operand bytes and a string describing the operands.
|
|
Packit |
5d935b |
The characters in the string have the following meaning:
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
c - lsb of class id
|
|
Packit |
5d935b |
C - msb of class id
|
|
Packit |
5d935b |
f - feature index
|
|
Packit |
5d935b |
g - lsb of glyph attribute id
|
|
Packit |
5d935b |
G - msb of glyph attribute id
|
|
Packit |
5d935b |
l - lsb of a 32-bit extension to a 16-bit number
|
|
Packit |
5d935b |
L - msb of a 32-bit number
|
|
Packit |
5d935b |
m - glyph metric id
|
|
Packit |
5d935b |
n - lsb of a number
|
|
Packit |
5d935b |
N - msb of a 16-bit number
|
|
Packit |
5d935b |
o - offset (jump)
|
|
Packit |
5d935b |
s - slot reference
|
|
Packit |
5d935b |
S - slot attribute id
|
|
Packit |
5d935b |
v - variable number of following arguments
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=cut
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
our @opcodes = ( ["nop", 0, ""], ["push_byte", 1, "n"], ["push_byte_u", 1, "n"], ["push_short", 2, "Nn"],
|
|
Packit |
5d935b |
["push_short_u", 2, "Nn"], ["push_long", 4, "LlNn"], ["add", 0, ""], ["sub", 0, ""],
|
|
Packit |
5d935b |
["mul", 0, ""], ["div", 0, ""], ["min", 0, ""], ["max", 0, ""],
|
|
Packit |
5d935b |
["neg", 0, ""], ["trunc8", 0, ""], ["trunc16", 0, ""], ["cond", 0, ""],
|
|
Packit |
5d935b |
["and", 0, ""], ["or", 0, ""], ["not", 0, ""], ["equal", 0, ""], # 16
|
|
Packit |
5d935b |
["not_eq", 0, ""], ["less", 0, ""], ["gtr", 0, ""], ["less_eq", 0, ""],
|
|
Packit |
5d935b |
["gtr_eq", 0, ""], ["next", 0, ""], ["next_n", 1, "n"], ["copy_next", 0, ""],
|
|
Packit |
5d935b |
["put_glyph_8bit_obs", 1, "c"], ["put_subs_8bit_obs", 3, "scc"], ["put_copy", 1, "s"], ["insert", 0, ""],
|
|
Packit |
5d935b |
["delete", 0, ""], ["assoc", -1, "v"], ["cntxt_item", 2, "so"], ["attr_set", 1, "S"], # 32
|
|
Packit |
5d935b |
["attr_add", 1, "S"], ["attr_sub", 1, "S"], ["attr_set_slot", 1, "S"], ["iattr_set_slot", 2, "Sn"],
|
|
Packit |
5d935b |
["push_slot_attr", 2, "Ss"], ["push_glyph_attr_obs", 2, "gs"], ["push_glyph_metric", 3, "msn"], ["push_feat", 2, "fs"],
|
|
Packit |
5d935b |
["push_att_to_gattr_obs", 2, "gs"], ["push_att_to_glyph_metric", 3, "msn"], ["push_islot_attr", 3, "Ssn"], ["push_iglyph_attr", 3, "gsn"],
|
|
Packit |
5d935b |
["pop_ret", 0, ""], ["ret_zero", 0, ""], ["ret_true", 0, ""], ["iattr_set", 2, "Sn"], # 48
|
|
Packit |
5d935b |
["iattr_add", 2, "Sn"], ["iattr_sub", 2, "Sn"], ["push_proc_state", 1, "n"], ["push_version", 0, ""],
|
|
Packit |
5d935b |
["put_subs", 5, "sCcCc"], ["put_subs2", 4, "cscc"], ["put_subs3", 7, "scscscc"], ["put_glyph", 2, "Cc"],
|
|
Packit |
5d935b |
["push_glyph_attr", 3, "Ggs"], ["push_att_to_glyph_attr", 3, "Ggs"], ["bitand", 0, ""], ["bitor", 0, ""],
|
|
Packit |
5d935b |
["bitnot", 0, ""], ["setbits", 4, "NnNn"], ["setfeat", 2, "fs"] ); # 64
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
my ($i) = 0;
|
|
Packit |
5d935b |
our %opnames = map {$_->[0] => $i++} @opcodes;
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=head2 read
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
Reads the Silf table into the internal data structure
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=cut
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
sub read
|
|
Packit |
5d935b |
{
|
|
Packit |
5d935b |
my ($self) = @_;
|
|
Packit |
5d935b |
$self->SUPER::read or return $self;
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
my ($dat, $d);
|
|
Packit |
5d935b |
my ($fh) = $self->{' INFILE'};
|
|
Packit |
5d935b |
my ($moff) = $self->{' OFFSET'};
|
|
Packit |
5d935b |
my ($numsilf, @silfo);
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
$fh->read($dat, 4);
|
|
Packit |
5d935b |
($self->{'Version'}) = TTF_Unpack("v", $dat);
|
|
Packit |
5d935b |
if ($self->{'Version'} >= 3)
|
|
Packit |
5d935b |
{
|
|
Packit |
5d935b |
$fh->read($dat, 4);
|
|
Packit |
5d935b |
($self->{'Compiler'}) = TTF_Unpack("v", $dat);
|
|
Packit |
5d935b |
}
|
|
Packit |
5d935b |
$fh->read($dat, 4);
|
|
Packit |
5d935b |
($numsilf) = TTF_Unpack("S", $dat);
|
|
Packit |
5d935b |
$fh->read($dat, $numsilf * 4);
|
|
Packit |
5d935b |
foreach my $i (0 .. $numsilf - 1)
|
|
Packit |
5d935b |
{ push (@silfo, TTF_Unpack("L", substr($dat, $i * 4, 4))); }
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
foreach my $sili (0 .. $numsilf - 1)
|
|
Packit |
5d935b |
{
|
|
Packit |
5d935b |
my ($silf) = {};
|
|
Packit |
5d935b |
my (@passo, @classo, $classbase, $numJust, $numCritFeatures, $numScript, $numPasses, $numPseudo, $i);
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
push (@{$self->{'SILF'}}, $silf);
|
|
Packit |
5d935b |
$fh->seek($moff + $silfo[$sili], 0);
|
|
Packit |
5d935b |
if ($self->{'Version'} >= 3)
|
|
Packit |
5d935b |
{
|
|
Packit |
5d935b |
$fh->read($dat, 8);
|
|
Packit |
5d935b |
($silf->{'Version'}) = TTF_Unpack("v", $dat);
|
|
Packit |
5d935b |
}
|
|
Packit |
5d935b |
$fh->read($dat, 20);
|
|
Packit |
5d935b |
($silf->{'maxGlyphID'}, $silf->{'Ascent'}, $silf->{'Descent'},
|
|
Packit |
5d935b |
$numPasses, $silf->{'substPass'}, $silf->{'posPass'}, $silf->{'justPass'}, $silf->{'bidiPass'},
|
|
Packit |
5d935b |
$silf->{'Flags'}, $silf->{'maxPreContext'}, $silf->{'maxPostContext'}, $silf->{'attrPseudo'},
|
|
Packit |
5d935b |
$silf->{'attrBreakWeight'}, $silf->{'attrDirectionality'}, $silf->{'attrMirror'}, $silf->{'passBits'}, $numJust) =
|
|
Packit |
5d935b |
TTF_Unpack("SssCCCCCCCCCCCCCC", $dat);
|
|
Packit |
5d935b |
if ($numJust)
|
|
Packit |
5d935b |
{
|
|
Packit |
5d935b |
foreach my $j (0 .. $silf->{'numJust'} - 1)
|
|
Packit |
5d935b |
{
|
|
Packit |
5d935b |
my ($just) = {};
|
|
Packit |
5d935b |
push (@{$silf->{'JUST'}}, $just);
|
|
Packit |
5d935b |
$fh->read($dat, 8);
|
|
Packit |
5d935b |
($just->{'attrStretch'}, $just->{'attrShrink'}, $just->{'attrStep'}, $just->{'attrWeight'},
|
|
Packit |
5d935b |
$just->{'runto'}) = TTF_Unpack("CCCCC", $dat);
|
|
Packit |
5d935b |
}
|
|
Packit |
5d935b |
}
|
|
Packit |
5d935b |
$fh->read($dat, 10);
|
|
Packit |
5d935b |
($silf->{'numLigComp'}, $silf->{'numUserAttr'}, $silf->{'maxCompPerLig'}, $silf->{'direction'},
|
|
Packit |
5d935b |
$silf->{'attCollisions'}, $d, $d, $d, $numCritFeatures) = TTF_Unpack("SCCCCCCCC", $dat);
|
|
Packit |
5d935b |
if ($numCritFeatures)
|
|
Packit |
5d935b |
{
|
|
Packit |
5d935b |
$fh->read($dat, $numCritFeatures * 2);
|
|
Packit |
5d935b |
$silf->{'CRIT_FEATURE'} = [TTF_Unpack("S$numCritFeatures", $dat)];
|
|
Packit |
5d935b |
}
|
|
Packit |
5d935b |
$fh->read($dat, 2);
|
|
Packit |
5d935b |
($d, $numScript) = TTF_Unpack("CC", $dat);
|
|
Packit |
5d935b |
if ($numScript)
|
|
Packit |
5d935b |
{
|
|
Packit |
5d935b |
$fh->read($dat, $numScript * 4);
|
|
Packit |
5d935b |
foreach (0 .. $numScript - 1)
|
|
Packit |
5d935b |
{ push (@{$silf->{'scripts'}}, unpack('a4', substr($dat, $_ * 4, 4))); }
|
|
Packit |
5d935b |
}
|
|
Packit |
5d935b |
$fh->read($dat, 2);
|
|
Packit |
5d935b |
($silf->{'lbGID'}) = TTF_Unpack("S", $dat);
|
|
Packit |
5d935b |
$fh->read($dat, $numPasses * 4 + 4);
|
|
Packit |
5d935b |
@passo = unpack("N*", $dat);
|
|
Packit |
5d935b |
$fh->read($dat, 8);
|
|
Packit |
5d935b |
($numPseudo) = TTF_Unpack("S", $dat);
|
|
Packit |
5d935b |
if ($numPseudo)
|
|
Packit |
5d935b |
{
|
|
Packit |
5d935b |
$fh->read($dat, $numPseudo * 6);
|
|
Packit |
5d935b |
foreach (0 .. $numPseudo - 1)
|
|
Packit |
5d935b |
{
|
|
Packit |
5d935b |
my ($uni, $gid) = TTF_Unpack("LS", substr($dat, $_ * 6, 6));
|
|
Packit |
5d935b |
$silf->{'pseudos'}{$uni} = $gid;
|
|
Packit |
5d935b |
}
|
|
Packit |
5d935b |
}
|
|
Packit |
5d935b |
$classbase = $fh->tell();
|
|
Packit |
5d935b |
$fh->read($dat, 4);
|
|
Packit |
5d935b |
my ($numClasses, $numLinearClasses) = TTF_Unpack("SS", $dat);
|
|
Packit |
5d935b |
$silf->{'numLinearClasses'} = $numLinearClasses;
|
|
Packit |
5d935b |
$fh->read($dat, ($numClasses + 1) * ($self->{'Version'} >= 4 ? 4 : 2));
|
|
Packit |
5d935b |
@classo = unpack($self->{'Version'} >= 4 ? "N*" : "n*", $dat);
|
|
Packit |
5d935b |
$fh->read($dat, $classo[-1] - $classo[0]);
|
|
Packit |
5d935b |
for ($i = 0; $i < $numLinearClasses; $i++)
|
|
Packit |
5d935b |
{
|
|
Packit |
5d935b |
push (@{$silf->{'classes'}}, [unpack("n*", substr($dat, $classo[$i] - $classo[0],
|
|
Packit |
5d935b |
$classo[$i+1] - $classo[$i]))])
|
|
Packit |
5d935b |
}
|
|
Packit |
5d935b |
for ($i = $numLinearClasses; $i < $numClasses; $i++)
|
|
Packit |
5d935b |
{
|
|
Packit |
5d935b |
my (@res);
|
|
Packit |
5d935b |
my (@c) = unpack("n*", substr($dat, $classo[$i] - $classo[0] + 8, $classo[$i+1] - $classo[$i] - 8));
|
|
Packit |
5d935b |
for (my $j = 0; $j < @c; $j += 2)
|
|
Packit |
5d935b |
{ $res[$c[$j+1]] = $c[$j]; }
|
|
Packit |
5d935b |
push (@{$silf->{'classes'}}, \@res);
|
|
Packit |
5d935b |
}
|
|
Packit |
5d935b |
foreach (0 .. $numPasses - 1)
|
|
Packit |
5d935b |
{ $self->read_pass($fh, $passo[$_], $moff + $silfo[$sili], $silf, $_); }
|
|
Packit |
5d935b |
}
|
|
Packit |
5d935b |
return $self;
|
|
Packit |
5d935b |
}
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
sub chopcode
|
|
Packit |
5d935b |
{
|
|
Packit |
5d935b |
my ($dest, $dat, $offsets, $isconstraint) = @_;
|
|
Packit |
5d935b |
my ($last) = $offsets->[-1];
|
|
Packit |
5d935b |
my ($i);
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
for ($i = $#{$offsets} - 1; $i >= 0; $i--)
|
|
Packit |
5d935b |
{
|
|
Packit |
5d935b |
if ((!$isconstraint || $offsets->[$i]) && $offsets->[$i] != $last)
|
|
Packit |
5d935b |
{
|
|
Packit |
5d935b |
unshift(@{$dest}, substr($dat, $offsets->[$i], $last - $offsets->[$i]));
|
|
Packit |
5d935b |
$last = $offsets->[$i];
|
|
Packit |
5d935b |
}
|
|
Packit |
5d935b |
else
|
|
Packit |
5d935b |
{ unshift(@{$dest}, ""); }
|
|
Packit |
5d935b |
}
|
|
Packit |
5d935b |
}
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
sub read_pass
|
|
Packit |
5d935b |
{
|
|
Packit |
5d935b |
my ($self, $fh, $offset, $base, $silf, $id) = @_;
|
|
Packit |
5d935b |
my ($pass) = {'id' => $id};
|
|
Packit |
5d935b |
my ($d, $dat, $i, @orulemap, @oconstraints, @oactions, $numRanges);
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
$fh->seek($offset + $base, 0);
|
|
Packit |
5d935b |
# printf "pass base = %04X\n", $offset;
|
|
Packit |
5d935b |
push (@{$silf->{'PASS'}}, $pass);
|
|
Packit |
5d935b |
$fh->read($dat, 40);
|
|
Packit |
5d935b |
($pass->{'flags'}, $pass->{'maxRuleLoop'}, $pass->{'maxRuleContext'}, $pass->{'maxBackup'},
|
|
Packit |
5d935b |
$pass->{'numRules'}, $d, $d, $d, $d, $d, $pass->{'numRows'}, $pass->{'numTransitional'},
|
|
Packit |
5d935b |
$pass->{'numSuccess'}, $pass->{'numColumns'}, $numRanges) =
|
|
Packit |
5d935b |
TTF_Unpack("CCCCSSLLLLSSSSS", $dat);
|
|
Packit |
5d935b |
$fh->read($dat, $numRanges * 6);
|
|
Packit |
5d935b |
foreach $i (0 .. $numRanges - 1)
|
|
Packit |
5d935b |
{
|
|
Packit |
5d935b |
my ($first, $last, $col) = TTF_Unpack('SSS', substr($dat, $i * 6, 6));
|
|
Packit |
5d935b |
foreach ($first .. $last)
|
|
Packit |
5d935b |
{ $pass->{'colmap'}{$_} = $col; }
|
|
Packit |
5d935b |
}
|
|
Packit |
5d935b |
$fh->read($dat, $pass->{'numSuccess'} * 2 + 2);
|
|
Packit |
5d935b |
@orulemap = unpack("n*", $dat);
|
|
Packit |
5d935b |
$fh->read($dat, $orulemap[-1] * 2);
|
|
Packit |
5d935b |
foreach (0 .. $pass->{'numSuccess'} - 1)
|
|
Packit |
5d935b |
{ push (@{$pass->{'rulemap'}}, [unpack("n*", substr($dat, $orulemap[$_] * 2, ($orulemap[$_+1] - $orulemap[$_]) * 2))]); }
|
|
Packit |
5d935b |
$fh->read($dat, 2);
|
|
Packit |
5d935b |
($pass->{'minRulePreContext'}, $pass->{'maxRulePreContext'}) = TTF_Unpack("CC", $dat);
|
|
Packit |
5d935b |
$fh->read($dat, ($pass->{'maxRulePreContext'} - $pass->{'minRulePreContext'} + 1) * 2);
|
|
Packit |
5d935b |
$pass->{'startStates'} = [unpack('n*', $dat)];
|
|
Packit |
5d935b |
$fh->read($dat, $pass->{'numRules'} * 2);
|
|
Packit |
5d935b |
$pass->{'ruleSortKeys'} = [unpack('n*', $dat)];
|
|
Packit |
5d935b |
$fh->read($dat, $pass->{'numRules'});
|
|
Packit |
5d935b |
$pass->{'rulePreContexts'} = [unpack('C*', $dat)];
|
|
Packit |
5d935b |
$fh->read($dat, 3);
|
|
Packit |
5d935b |
($pass->{'collisionThreshold'}, $pass->{'passConstraintLen'}) = TTF_Unpack("CS", $dat);
|
|
Packit |
5d935b |
$fh->read($dat, ($pass->{'numRules'} + 1) * 2);
|
|
Packit |
5d935b |
@oconstraints = unpack('n*', $dat);
|
|
Packit |
5d935b |
$fh->read($dat, ($pass->{'numRules'} + 1) * 2);
|
|
Packit |
5d935b |
@oactions = unpack('n*', $dat);
|
|
Packit |
5d935b |
foreach (0 .. $pass->{'numTransitional'} - 1)
|
|
Packit |
5d935b |
{
|
|
Packit |
5d935b |
$fh->read($dat, $pass->{'numColumns'} * 2);
|
|
Packit |
5d935b |
push (@{$pass->{'fsm'}}, [unpack('n*', $dat)]);
|
|
Packit |
5d935b |
}
|
|
Packit |
5d935b |
$fh->read($dat, 1);
|
|
Packit |
5d935b |
if ($pass->{'passConstraintLen'})
|
|
Packit |
5d935b |
{ $fh->read($pass->{'passConstraintCode'}, $pass->{'passConstraintLen'}); }
|
|
Packit |
5d935b |
$fh->read($dat, $oconstraints[-1]);
|
|
Packit |
5d935b |
$pass->{'constraintCode'} = [];
|
|
Packit |
5d935b |
chopcode($pass->{'constraintCode'}, $dat, \@oconstraints, 1);
|
|
Packit |
5d935b |
$fh->read($dat, $oactions[-1]);
|
|
Packit |
5d935b |
$pass->{'actionCode'} = [];
|
|
Packit |
5d935b |
chopcode($pass->{'actionCode'}, $dat, \@oactions, 0);
|
|
Packit |
5d935b |
return $pass;
|
|
Packit |
5d935b |
}
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
sub chopranges
|
|
Packit |
5d935b |
{
|
|
Packit |
5d935b |
my ($map, $numg) = @_;
|
|
Packit |
5d935b |
my ($dat, $numRanges);
|
|
Packit |
5d935b |
my (@keys) = sort {$a <=> $b} keys %{$map};
|
|
Packit |
5d935b |
my ($first, $last, $col, $g);
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
$first = -1;
|
|
Packit |
5d935b |
$last = -1;
|
|
Packit |
5d935b |
$col = -1;
|
|
Packit |
5d935b |
foreach $g (@keys)
|
|
Packit |
5d935b |
{
|
|
Packit |
5d935b |
next unless ($g > 0 or $g eq '0');
|
|
Packit |
5d935b |
if ($g != $last + 1 || $map->{$g} != $col)
|
|
Packit |
5d935b |
{
|
|
Packit |
5d935b |
if ($col != -1)
|
|
Packit |
5d935b |
{
|
|
Packit |
5d935b |
$dat .= pack("nnn", $first, $last, $col);
|
|
Packit |
5d935b |
$numRanges++;
|
|
Packit |
5d935b |
}
|
|
Packit |
5d935b |
$first = $last = $g;
|
|
Packit |
5d935b |
$col = $map->{$g};
|
|
Packit |
5d935b |
}
|
|
Packit |
5d935b |
else
|
|
Packit |
5d935b |
{ $last++; }
|
|
Packit |
5d935b |
}
|
|
Packit |
5d935b |
if ($col != -1)
|
|
Packit |
5d935b |
{
|
|
Packit |
5d935b |
$dat .= pack("nnn", $first, $last, $col);
|
|
Packit |
5d935b |
$numRanges++;
|
|
Packit |
5d935b |
}
|
|
Packit |
5d935b |
return ($numRanges, $dat);
|
|
Packit |
5d935b |
}
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
sub unpack_code
|
|
Packit |
5d935b |
{
|
|
Packit |
5d935b |
my ($self, $str) = @_;
|
|
Packit |
5d935b |
my (@res, $i, $j);
|
|
Packit |
5d935b |
my ($l) = length($str);
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
for ($i = 0; $i < $l; )
|
|
Packit |
5d935b |
{
|
|
Packit |
5d935b |
my ($a) = unpack('C', substr($str, $i, 1));
|
|
Packit |
5d935b |
my ($o) = $opcodes[$a];
|
|
Packit |
5d935b |
my (@args);
|
|
Packit |
5d935b |
my (@types) = split('', $o->[2]);
|
|
Packit |
5d935b |
++$i;
|
|
Packit |
5d935b |
for ($j = 0; $j < @types; ++$j)
|
|
Packit |
5d935b |
{
|
|
Packit |
5d935b |
my ($t) = $types[$j];
|
|
Packit |
5d935b |
if ($t eq 'v')
|
|
Packit |
5d935b |
{
|
|
Packit |
5d935b |
my ($n) = unpack('C', substr($str, $i, 1));
|
|
Packit |
5d935b |
push (@args, unpack('C*', substr($str, $i + 1, $n)));
|
|
Packit |
5d935b |
$i += $n + 1;
|
|
Packit |
5d935b |
}
|
|
Packit |
5d935b |
elsif ($t eq 'L' or $t eq 'N' or $t eq 'G' or $t eq 'C')
|
|
Packit |
5d935b |
{
|
|
Packit |
5d935b |
push (@args, unpack('n', substr($str, $i, 2)));
|
|
Packit |
5d935b |
$i += 2;
|
|
Packit |
5d935b |
$j++;
|
|
Packit |
5d935b |
}
|
|
Packit |
5d935b |
else
|
|
Packit |
5d935b |
{
|
|
Packit |
5d935b |
push (@args, unpack($t eq 's' ? 'c' : 'C', substr($str, $i, 1)));
|
|
Packit |
5d935b |
$i++;
|
|
Packit |
5d935b |
}
|
|
Packit |
5d935b |
}
|
|
Packit |
5d935b |
push (@res, [$o->[0], @args]);
|
|
Packit |
5d935b |
}
|
|
Packit |
5d935b |
return @res;
|
|
Packit |
5d935b |
}
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
sub pack_code
|
|
Packit |
5d935b |
{
|
|
Packit |
5d935b |
my ($self, $cmds) = @_;
|
|
Packit |
5d935b |
my ($res);
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
foreach my $c (@{$cmds})
|
|
Packit |
5d935b |
{
|
|
Packit |
5d935b |
my ($ind) = $opnames{$c->[0]};
|
|
Packit |
5d935b |
my ($i) = 1;
|
|
Packit |
5d935b |
$res .= pack('C', $ind);
|
|
Packit |
5d935b |
# my (@types) = unpack('C*', $opcodes[$ind][2]);
|
|
Packit |
5d935b |
my (@types) = split('', $opcodes[$ind][2]);
|
|
Packit |
5d935b |
for (my $j = 0; $j < @types; $j++)
|
|
Packit |
5d935b |
{
|
|
Packit |
5d935b |
my ($t) = $types[$j];
|
|
Packit |
5d935b |
if ($t eq 'v')
|
|
Packit |
5d935b |
{
|
|
Packit |
5d935b |
my ($n) = scalar @{$c} - 1;
|
|
Packit |
5d935b |
$res .= pack('C*', $n, @{$c}[1..$#{$c}]);
|
|
Packit |
5d935b |
$i += $n;
|
|
Packit |
5d935b |
}
|
|
Packit |
5d935b |
elsif ($t eq 'C' or $t eq 'G' or $t eq 'L' or $t eq 'N')
|
|
Packit |
5d935b |
{
|
|
Packit |
5d935b |
$res .= pack('n', $c->[$i]);
|
|
Packit |
5d935b |
$j++;
|
|
Packit |
5d935b |
}
|
|
Packit |
5d935b |
else
|
|
Packit |
5d935b |
{ $res .= pack($t eq 's' ? 'c' : 'C', $c->[$i]); }
|
|
Packit |
5d935b |
$i++;
|
|
Packit |
5d935b |
}
|
|
Packit |
5d935b |
}
|
|
Packit |
5d935b |
return $res;
|
|
Packit |
5d935b |
}
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
sub packcode
|
|
Packit |
5d935b |
{
|
|
Packit |
5d935b |
my ($code, $isconstraint) = @_;
|
|
Packit |
5d935b |
my ($dat, $c, $res);
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
$c = 1;
|
|
Packit |
5d935b |
$dat = "\000";
|
|
Packit |
5d935b |
foreach (@{$code})
|
|
Packit |
5d935b |
{
|
|
Packit |
5d935b |
if ($_)
|
|
Packit |
5d935b |
{
|
|
Packit |
5d935b |
push(@{$res}, $c);
|
|
Packit |
5d935b |
$dat .= $_;
|
|
Packit |
5d935b |
$c += length($_);
|
|
Packit |
5d935b |
}
|
|
Packit |
5d935b |
else
|
|
Packit |
5d935b |
{ push(@{$res}, $isconstraint ? 0 : $c); }
|
|
Packit |
5d935b |
}
|
|
Packit |
5d935b |
push(@{$res}, $c);
|
|
Packit |
5d935b |
return ($res, $dat);
|
|
Packit |
5d935b |
}
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
sub out_pass
|
|
Packit |
5d935b |
{
|
|
Packit |
5d935b |
my ($self, $fh, $pass, $silf, $subbase) = @_;
|
|
Packit |
5d935b |
my (@orulemap, $dat, $actiondat, $numRanges, $c);
|
|
Packit |
5d935b |
my (@offsets, $res, $pbase);
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
$pbase = $fh->tell();
|
|
Packit |
5d935b |
# printf "pass base = %04X, ", $pbase - $subbase;
|
|
Packit |
5d935b |
$fh->print(TTF_Pack("CCCCSSLLLLSSSS", $pass->{'flags'}, $pass->{'maxRuleLoop'}, $pass->{'maxRuleContext'},
|
|
Packit |
5d935b |
$pass->{'maxBackup'}, $pass->{'numRules'}, 24, 0, 0, 0, 0, $pass->{'numRows'},
|
|
Packit |
5d935b |
$pass->{'numTransitional'}, $pass->{'numSuccess'}, $pass->{'numColumns'}));
|
|
Packit |
5d935b |
($numRanges, $dat) = chopranges($pass->{'colmap'});
|
|
Packit |
5d935b |
# print "numranges = $numRanges\n";
|
|
Packit |
5d935b |
$fh->print(TTF_Pack("SSSS", TTF_bininfo($numRanges, 6)));
|
|
Packit |
5d935b |
$fh->print($dat);
|
|
Packit |
5d935b |
$dat = "";
|
|
Packit |
5d935b |
$c = 0;
|
|
Packit |
5d935b |
# print "transitions = $pass->{'numTransitional'}, success = $pass->{'numSuccess'}, rows = $pass->{'numRows'}\n";
|
|
Packit |
5d935b |
my ($sucbase) = $pass->{'numRows'} - $pass->{'numSuccess'};
|
|
Packit |
5d935b |
foreach (0 .. ($pass->{'numSuccess'} - 1))
|
|
Packit |
5d935b |
{
|
|
Packit |
5d935b |
push(@orulemap, $c);
|
|
Packit |
5d935b |
if (defined $pass->{'rulemap'}[$_])
|
|
Packit |
5d935b |
{
|
|
Packit |
5d935b |
$dat .= pack("n*", @{$pass->{'rulemap'}[$_]});
|
|
Packit |
5d935b |
$c += @{$pass->{'rulemap'}[$_]};
|
|
Packit |
5d935b |
}
|
|
Packit |
5d935b |
else
|
|
Packit |
5d935b |
{
|
|
Packit |
5d935b |
print "No rules for " . ($sucbase + $_);
|
|
Packit |
5d935b |
if ($sucbase + $_ < $pass->{'numTransitional'})
|
|
Packit |
5d935b |
{ print ": (" . join(",", @{$pass->{'fsm'}[$sucbase + $_]}) . ")"; }
|
|
Packit |
5d935b |
print "\n";
|
|
Packit |
5d935b |
}
|
|
Packit |
5d935b |
}
|
|
Packit |
5d935b |
push (@orulemap, $c);
|
|
Packit |
5d935b |
$fh->print(pack("n*", @orulemap));
|
|
Packit |
5d935b |
$fh->print($dat);
|
|
Packit |
5d935b |
$fh->print(TTF_Pack("CC", $pass->{'minRulePreContext'}, $pass->{'maxRulePreContext'}));
|
|
Packit |
5d935b |
$fh->print(pack("n*", @{$pass->{'startStates'}}));
|
|
Packit |
5d935b |
$fh->print(pack("n*", @{$pass->{'ruleSortKeys'}}));
|
|
Packit |
5d935b |
$fh->print(pack("C*", @{$pass->{'rulePreContexts'}}));
|
|
Packit |
5d935b |
$fh->print(TTF_Pack("CS", 0, $pass->{'passConstraintLen'}));
|
|
Packit |
5d935b |
my ($oconstraints, $oactions);
|
|
Packit |
5d935b |
($oconstraints, $dat) = packcode($pass->{'constraintCode'}, 1);
|
|
Packit |
5d935b |
($oactions, $actiondat) = packcode($pass->{'actionCode'}, 0);
|
|
Packit |
5d935b |
# printf "constraint offsets @ %X\n", $fh->tell();
|
|
Packit |
5d935b |
$fh->print(pack("n*", @{$oconstraints}));
|
|
Packit |
5d935b |
# printf "action offsets @ %X\n", $fh->tell();
|
|
Packit |
5d935b |
$fh->print(pack("n*", @{$oactions}));
|
|
Packit |
5d935b |
# printf "fsm @ %X\n", $fh->tell();
|
|
Packit |
5d935b |
foreach (@{$pass->{'fsm'}})
|
|
Packit |
5d935b |
{ $fh->print(pack("n*", @{$_})); }
|
|
Packit |
5d935b |
# printf "end of fsm @ %X\n", $fh->tell();
|
|
Packit |
5d935b |
$fh->print(pack("C", $pass->{'collisionThreshold'}));
|
|
Packit |
5d935b |
push(@offsets, $fh->tell() - $subbase);
|
|
Packit |
5d935b |
$fh->print($pass->{'passConstraintCode'});
|
|
Packit |
5d935b |
push(@offsets, $fh->tell() - $subbase);
|
|
Packit |
5d935b |
$fh->print($dat);
|
|
Packit |
5d935b |
push(@offsets, $fh->tell() - $subbase);
|
|
Packit |
5d935b |
$fh->print($actiondat);
|
|
Packit |
5d935b |
push(@offsets, 0);
|
|
Packit |
5d935b |
print join(", ", @offsets) . "\n";
|
|
Packit |
5d935b |
$res = $fh->tell();
|
|
Packit |
5d935b |
$fh->seek($pbase + 8, 0);
|
|
Packit |
5d935b |
$fh->print(pack("N*", @offsets));
|
|
Packit |
5d935b |
$fh->seek($res, 0);
|
|
Packit |
5d935b |
# printf "end = %04X\n", $res - $subbase;
|
|
Packit |
5d935b |
return $res;
|
|
Packit |
5d935b |
}
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=head2 out
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
Outputs a Silf data structure to a font file in binary format
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=cut
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
sub out
|
|
Packit |
5d935b |
{
|
|
Packit |
5d935b |
my ($self, $fh) = @_;
|
|
Packit |
5d935b |
my ($silf, $base, $subbase, $silfc, $end);
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
return $self->SUPER::out($fh) unless ($self->{' read'});
|
|
Packit |
5d935b |
$base = $fh->tell();
|
|
Packit |
5d935b |
if ($self->{'Version'} >= 3)
|
|
Packit |
5d935b |
{ $fh->print(TTF_Pack("vvSS", $self->{'Version'}, $self->{'Compiler'}, $#{$self->{'SILF'}} + 1, 0)); }
|
|
Packit |
5d935b |
else
|
|
Packit |
5d935b |
{ $fh->print(TTF_Pack("vSS", $self->{'Version'}, $#{$self->{'SILF'}} + 1, 0)); }
|
|
Packit |
5d935b |
$fh->print(pack('N*', (0) x (@{$self->{'SILF'}})));
|
|
Packit |
5d935b |
foreach $silf (@{$self->{'SILF'}})
|
|
Packit |
5d935b |
{
|
|
Packit |
5d935b |
my ($subbase) = $fh->tell();
|
|
Packit |
5d935b |
my ($numlin, $i, @opasses, $oPasses, $oPseudo, $ooPasses);
|
|
Packit |
5d935b |
if ($self->{'Version'} >= 3)
|
|
Packit |
5d935b |
{
|
|
Packit |
5d935b |
$fh->seek($base + 12 + $silfc * 4, 0);
|
|
Packit |
5d935b |
$fh->print(pack('N', $subbase - $base));
|
|
Packit |
5d935b |
$fh->seek($subbase, 0);
|
|
Packit |
5d935b |
$fh->print(TTF_Pack("vSS", $silf->{'Version'}, $ooPasses, $oPseudo));
|
|
Packit |
5d935b |
}
|
|
Packit |
5d935b |
else
|
|
Packit |
5d935b |
{
|
|
Packit |
5d935b |
$fh->seek($base + 8 + $silfc * 4, 0);
|
|
Packit |
5d935b |
$fh->print(pack('N', $subbase - $base));
|
|
Packit |
5d935b |
$fh->seek($subbase, 0);
|
|
Packit |
5d935b |
}
|
|
Packit |
5d935b |
$fh->print(TTF_Pack("SssCCCCCCCCCCCCCC",
|
|
Packit |
5d935b |
$silf->{'maxGlyphID'}, $silf->{'Ascent'}, $silf->{'Descent'},
|
|
Packit |
5d935b |
scalar @{$silf->{'PASS'}}, $silf->{'substPass'}, $silf->{'posPass'}, $silf->{'justPass'}, $silf->{'bidiPass'},
|
|
Packit |
5d935b |
$silf->{'Flags'}, $silf->{'maxPreContext'}, $silf->{'maxPostContext'}, $silf->{'attrPseudo'},
|
|
Packit |
5d935b |
$silf->{'attrBreakWeight'}, $silf->{'attrDirectionality'}, $silf->{'attrMirror'}, $silf->{'passBits'}, $#{$silf->{'JUST'}} + 1));
|
|
Packit |
5d935b |
foreach (@{$silf->{'JUST'}})
|
|
Packit |
5d935b |
{ $fh->print(TTF_Pack("CCCCCCCC", $_->{'attrStretch'}, $_->{'attrShrink'}, $_->{'attrStep'},
|
|
Packit |
5d935b |
$_->{'attrWeight'}, $_->{'runto'}, 0, 0, 0)); }
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
$fh->print(TTF_Pack("SCCCCCCCC", $silf->{'numLigComp'}, $silf->{'numUserAttr'}, $silf->{'maxCompPerLig'},
|
|
Packit |
5d935b |
$silf->{'direction'}, $silf->{'attCollisions'}, 0, 0, 0, $#{$silf->{'CRIT_FEATURE'}} + 1));
|
|
Packit |
5d935b |
$fh->print(pack("n*", @{$silf->{'CRIT_FEATURE'}}));
|
|
Packit |
5d935b |
$fh->print(TTF_Pack("CC", 0, $#{$silf->{'scripts'}} + 1));
|
|
Packit |
5d935b |
foreach (@{$self->{'scripts'}})
|
|
Packit |
5d935b |
{ $fh->print(pack("a4", $_)); }
|
|
Packit |
5d935b |
$fh->print(TTF_Pack("S", $silf->{'lbGID'}));
|
|
Packit |
5d935b |
$ooPasses = $fh->tell();
|
|
Packit |
5d935b |
if ($silf->{'PASS'}) { $fh->print(pack("N*", (0) x (@{$silf->{'PASS'}} + 1)));}
|
|
Packit |
5d935b |
$oPseudo = $fh->tell() - $subbase;
|
|
Packit |
5d935b |
my (@pskeys) = keys %{$silf->{'pseudos'}};
|
|
Packit |
5d935b |
$fh->print(TTF_Pack("SSSS", TTF_bininfo(scalar @pskeys, 6)));
|
|
Packit |
5d935b |
foreach my $k (sort {$a <=> $b} @pskeys)
|
|
Packit |
5d935b |
{ $fh->print(TTF_Pack("Ls", $k, $silf->{'pseudos'}{$k})); }
|
|
Packit |
5d935b |
$numlin = $silf->{'numLinearClasses'};
|
|
Packit |
5d935b |
$fh->print(TTF_Pack("SS", scalar @{$silf->{'classes'}}, $numlin));
|
|
Packit |
5d935b |
my (@coffsets);
|
|
Packit |
5d935b |
# printf "%X, ", $fh->tell() - $base;
|
|
Packit |
5d935b |
my ($cbase) = (scalar @{$silf->{'classes'}} + 1) * ($self->{'Version'} >= 4 ? 4 : 2) + 4;
|
|
Packit |
5d935b |
for ($i = 0; $i < $numlin; $i++)
|
|
Packit |
5d935b |
{
|
|
Packit |
5d935b |
push (@coffsets, $cbase);
|
|
Packit |
5d935b |
$cbase += 2 * scalar @{$silf->{'classes'}[$i]};
|
|
Packit |
5d935b |
}
|
|
Packit |
5d935b |
my (@nonlinclasses);
|
|
Packit |
5d935b |
for ($i = $numlin; $i < @{$silf->{'classes'}}; $i++)
|
|
Packit |
5d935b |
{
|
|
Packit |
5d935b |
my (@c, $d, @d);
|
|
Packit |
5d935b |
my $c = $silf->{'classes'}[$i];
|
|
Packit |
5d935b |
push (@coffsets, $cbase);
|
|
Packit |
5d935b |
@c = sort {$c->[$a] <=> $c->[$b]} (0 .. $#{$c});
|
|
Packit |
5d935b |
foreach $d (@c)
|
|
Packit |
5d935b |
{ push (@d, $c->[$d], $d); }
|
|
Packit |
5d935b |
push (@nonlinclasses, [@d]);
|
|
Packit |
5d935b |
my ($len) = scalar @d;
|
|
Packit |
5d935b |
$cbase += 8 + 2 * $len;
|
|
Packit |
5d935b |
}
|
|
Packit |
5d935b |
push (@coffsets, $cbase);
|
|
Packit |
5d935b |
$fh->print(pack(($self->{'Version'} >= 4 ? 'N*' : 'n*'), @coffsets));
|
|
Packit |
5d935b |
for ($i = 0; $i < $numlin; $i++)
|
|
Packit |
5d935b |
{ $fh->print(pack("n*", @{$silf->{'classes'}[$i]})); }
|
|
Packit |
5d935b |
# printf "%X, ", $fh->tell() - $base;
|
|
Packit |
5d935b |
for ($i = $numlin; $i < @{$silf->{'classes'}}; $i++)
|
|
Packit |
5d935b |
{
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
my ($num) = scalar @{$nonlinclasses[$i-$numlin]};
|
|
Packit |
5d935b |
my (@bin) = TTF_bininfo($num/2, 1);
|
|
Packit |
5d935b |
$fh->print(TTF_Pack("SSSS", @bin));
|
|
Packit |
5d935b |
$fh->print(pack("n*", @{$nonlinclasses[$i-$numlin]}));
|
|
Packit |
5d935b |
}
|
|
Packit |
5d935b |
$oPasses = $fh->tell() - $subbase;
|
|
Packit |
5d935b |
# printf "original pass = %04X\n", $oPasses;
|
|
Packit |
5d935b |
push (@opasses, $oPasses);
|
|
Packit |
5d935b |
foreach (@{$silf->{'PASS'}})
|
|
Packit |
5d935b |
{ push(@opasses, $self->out_pass($fh, $_, $silf, $subbase) - $subbase); }
|
|
Packit |
5d935b |
$end = $fh->tell();
|
|
Packit |
5d935b |
$fh->seek($ooPasses, 0);
|
|
Packit |
5d935b |
$fh->print(pack("N*", @opasses));
|
|
Packit |
5d935b |
if ($self->{'Version'} >= 3)
|
|
Packit |
5d935b |
{
|
|
Packit |
5d935b |
$fh->seek($subbase + 4, 0);
|
|
Packit |
5d935b |
$fh->print(TTF_Pack("SS", $ooPasses - $subbase, $oPseudo));
|
|
Packit |
5d935b |
}
|
|
Packit |
5d935b |
$fh->seek($end, 0);
|
|
Packit |
5d935b |
$silfc++;
|
|
Packit |
5d935b |
}
|
|
Packit |
5d935b |
}
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
sub XML_element
|
|
Packit |
5d935b |
{
|
|
Packit |
5d935b |
my ($self, $context, $depth, $k, $val, $ind) = @_;
|
|
Packit |
5d935b |
my ($fh) = $context->{'fh'};
|
|
Packit |
5d935b |
my ($i);
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
return $self if ($k eq 'LOC');
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
if ($k eq 'classes')
|
|
Packit |
5d935b |
{
|
|
Packit |
5d935b |
$fh->print("$depth<classes>\n");
|
|
Packit |
5d935b |
foreach $i (0 .. $#{$val})
|
|
Packit |
5d935b |
{
|
|
Packit |
5d935b |
$fh->printf("$depth <class num='%d'>\n", $i);
|
|
Packit |
5d935b |
$fh->printf("$depth " . join(" ", map{sprintf("%d", $_)} @{$val->[$i]}));
|
|
Packit |
5d935b |
$fh->print("\n$depth </class>\n");
|
|
Packit |
5d935b |
}
|
|
Packit |
5d935b |
$fh->print("$depth</classes>\n");
|
|
Packit |
5d935b |
}
|
|
Packit |
5d935b |
elsif ($k eq 'fsm')
|
|
Packit |
5d935b |
{
|
|
Packit |
5d935b |
$fh->print("$depth<fsm>\n");
|
|
Packit |
5d935b |
my ($i) = 0;
|
|
Packit |
5d935b |
foreach (@{$val})
|
|
Packit |
5d935b |
{ $fh->print("$depth <row index='$i'>" . join(" ", @{$_}) . "</row>\n"); $i++; }
|
|
Packit |
5d935b |
$fh->print("$depth</fsm>\n");
|
|
Packit |
5d935b |
}
|
|
Packit |
5d935b |
elsif ($k eq 'colmap')
|
|
Packit |
5d935b |
{
|
|
Packit |
5d935b |
my ($i);
|
|
Packit |
5d935b |
$fh->print("$depth<colmap>");
|
|
Packit |
5d935b |
foreach my $k (sort {$a <=> $b} keys %{$val})
|
|
Packit |
5d935b |
{
|
|
Packit |
5d935b |
if ($i++ % 8 == 0)
|
|
Packit |
5d935b |
{ $fh->print("\n$depth "); }
|
|
Packit |
5d935b |
$fh->printf(" %d=%d", $k, $val->{$k});
|
|
Packit |
5d935b |
}
|
|
Packit |
5d935b |
$fh->print("\n$depth</colmap>\n");
|
|
Packit |
5d935b |
}
|
|
Packit |
5d935b |
elsif ($k eq 'constraintCode' or $k eq 'actionCode')
|
|
Packit |
5d935b |
{
|
|
Packit |
5d935b |
$fh->print("$depth<$k>\n");
|
|
Packit |
5d935b |
foreach my $i (0 .. $#{$val})
|
|
Packit |
5d935b |
{
|
|
Packit |
5d935b |
my (@rules) = $self->unpack_code($val->[$i]);
|
|
Packit |
5d935b |
next unless (@rules);
|
|
Packit |
5d935b |
$fh->print("$depth <elem index='$i' code='" . join(" ", unpack('C*', $val->[$i])) . "'>\n");
|
|
Packit |
5d935b |
foreach my $r (@rules)
|
|
Packit |
5d935b |
{ $fh->print("$depth $r->[0]: ". join(", ", @{$r}[1..$#{$r}]) . "\n"); }
|
|
Packit |
5d935b |
$fh->print("$depth </elem>\n");
|
|
Packit |
5d935b |
}
|
|
Packit |
5d935b |
$fh->print("$depth</$k>\n");
|
|
Packit |
5d935b |
}
|
|
Packit |
5d935b |
else
|
|
Packit |
5d935b |
{ return $self->SUPER::XML_element($context, $depth, $k, $val, $ind); }
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
$self;
|
|
Packit |
5d935b |
}
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=head2 $t->minsize()
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
Returns the minimum size this table can be. If it is smaller than this, then the table
|
|
Packit |
5d935b |
must be bad and should be deleted or whatever.
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=cut
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
sub minsize
|
|
Packit |
5d935b |
{
|
|
Packit |
5d935b |
return 4;
|
|
Packit |
5d935b |
}
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
1;
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=head1 AUTHOR
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
Martin Hosken L<http://scripts.sil.org/FontUtils>.
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=head1 LICENSING
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
Copyright (c) 1998-2016, SIL International (http://www.sil.org)
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
This module is released under the terms of the Artistic License 2.0.
|
|
Packit |
5d935b |
For details, see the full text of the license in the file LICENSE.
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
|
|
Packit |
5d935b |
=cut
|