1package Font::TTF::OldMort;
2
3=head1 NAME
4
5Font::TTF::OldMort - Glyph Metamorphosis table in a font
6
7=head1 DESCRIPTION
8
9=head1 INSTANCE VARIABLES
10
11=over
12
13=item version
14
15table version number (Fixed: currently 1.0)
16
17=item chains
18
19list of metamorphosis chains, each of which has its own fields:
20
21=over
22
23=item defaultFlags
24
25chain's default subfeature flags (UInt32)
26
27=item featureEntries
28
29list of feature entries, each of which has fields:
30
31=over
32
33=item type
34
35=item setting
36
37=item enable
38
39=item disable
40
41=back
42
43=item subtables
44
45list of metamorphosis subtables, each of which has fields:
46
47=over
48
49=item type
50
51subtable type (0: rearrangement; 1: contextual substitution; 2: ligature;
524: non-contextual substitution; 5: insertion)
53
54=item direction
55
56processing direction ('LR' or 'RL')
57
58=item orientation
59
60applies to text in which orientation ('VH', 'V', or 'H')
61
62=item subFeatureFlags
63
64the subfeature flags controlling whether the table is used (UInt32)
65
66=back
67
68Further fields depend on the type of subtable:
69
70=over
71
72Rearrangement table:
73
74=over
75
76=item classes
77
78array of lists of glyphs
79
80=item states
81
82array of arrays of hashes{'nextState', 'flags'}
83
84=back
85
86Contextual substitution table:
87
88=over
89
90=item classes
91
92array of lists of glyphs
93
94=item states
95
96array of array of hashes{'nextState', 'flags', 'actions'}, where C<actions>
97is an array of two elements which are offsets to be added to [marked, current]
98glyph to get index into C<mappings> (or C<undef> if no mapping to be applied)
99
100=item mappings
101
102list of glyph codes mapped to through the state table mappings
103
104=back
105
106Ligature table:
107
108Non-contextual substitution table:
109
110Insertion table:
111
112=back
113
114=back
115
116=back
117
118=head1 METHODS
119
120=cut
121
122use strict;
123use vars qw(@ISA);
124use Font::TTF::Utils;
125use Font::TTF::AATutils;
126use IO::File;
127
128@ISA = qw(Font::TTF::Table);
129
130=over
131
132=back
133
134=head2 $t->read
135
136Reads the table into memory
137
138=cut
139
140sub read
141{
142    my ($self) = @_;
143    my ($dat, $fh, $numChains);
144
145    $self->SUPER::read or return $self;
146
147    $fh = $self->{' INFILE'};
148
149    $fh->read($dat, 8);
150    ($self->{'version'}, $numChains) = TTF_Unpack("fL", $dat);
151
152    my $chains = [];
153    foreach (1 .. $numChains) {
154        my $chainStart = $fh->tell();
155        $fh->read($dat, 12);
156        my ($defaultFlags, $chainLength, $nFeatureEntries, $nSubtables) = TTF_Unpack("LLSS", $dat);
157        my $featureEntries = [];
158        foreach (1 .. $nFeatureEntries) {
159            $fh->read($dat, 12);
160            my ($featureType, $featureSetting, $enableFlags, $disableFlags) = TTF_Unpack("SSLL", $dat);
161            push @$featureEntries,    {
162                                        'type'        => $featureType,
163                                        'setting'    => $featureSetting,
164                                        'enable'    => $enableFlags,
165                                        'disable'    => $disableFlags
166                                    };
167        }
168        my $subtables = [];
169        foreach (1 .. $nSubtables) {
170            my $subtableStart = $fh->tell();
171            $fh->read($dat, 8);
172            my ($length, $coverage, $subFeatureFlags) = TTF_Unpack("SSL", $dat);
173            my $type = $coverage & 0x0007;
174
175            my $subtable =    {
176                                'type'                => $type,
177                                'direction'            => (($coverage & 0x4000) ? 'RL' : 'LR'),
178                                'orientation'        => (($coverage & 0x2000) ? 'VH' : ($coverage & 0x8000) ? 'V' : 'H'),
179                                'subFeatureFlags'    => $subFeatureFlags
180                            };
181
182            if ($type == 0) {    # rearrangement
183                my ($classes, $states) = AAT_read_state_table($fh, 0);
184                $subtable->{'classes'} = $classes;
185                $subtable->{'states'} = $states;
186            }
187
188            elsif ($type == 1) {    # contextual
189                my $stateTableStart = $fh->tell();
190                my ($classes, $states, $entries) = AAT_read_state_table($fh, 2);
191
192                $fh->seek($stateTableStart, IO::File::SEEK_SET);
193                $fh->read($dat, 10);
194                my ($stateSize, $classTable, $stateArray, $entryTable, $mappingTables) = unpack("nnnnn", $dat);
195                my $limits = [$classTable, $stateArray, $entryTable, $mappingTables, $length - 8];
196
197                foreach (@$entries) {
198                    my $actions = $_->{'actions'};
199                    foreach (@$actions) {
200                        $_ = $_ ? $_ - ($mappingTables / 2) : undef;
201                    }
202                }
203
204                $subtable->{'classes'} = $classes;
205                $subtable->{'states'} = $states;
206                $subtable->{'mappings'} = [unpack("n*", AAT_read_subtable($fh, $stateTableStart, $mappingTables, $limits))];
207            }
208
209            elsif ($type == 2) {    # ligature
210                my $stateTableStart = $fh->tell();
211                my ($classes, $states, $entries) = AAT_read_state_table($fh, 0);
212
213                $fh->seek($stateTableStart, IO::File::SEEK_SET);
214                $fh->read($dat, 14);
215                my ($stateSize, $classTable, $stateArray, $entryTable,
216                    $ligActionTable, $componentTable, $ligatureTable) = unpack("nnnnnnn", $dat);
217                my $limits = [$classTable, $stateArray, $entryTable, $ligActionTable, $componentTable, $ligatureTable, $length - 8];
218
219                my %actions;
220                my $actionLists;
221                foreach (@$entries) {
222                    my $offset = $_->{'flags'} & 0x3fff;
223                    $_->{'flags'} &= ~0x3fff;
224                    if ($offset != 0) {
225                        if (not defined $actions{$offset}) {
226                            $fh->seek($stateTableStart + $offset, IO::File::SEEK_SET);
227                            my $actionList;
228                            while (1) {
229                                $fh->read($dat, 4);
230                                my $action = unpack("N", $dat);
231                                my ($last, $store, $component) = (($action & 0x80000000) != 0, ($action & 0xC0000000) != 0, ($action & 0x3fffffff));
232                                $component -= 0x40000000 if $component > 0x1fffffff;
233                                $component -= $componentTable / 2;
234                                push @$actionList, { 'store' => $store, 'component' => $component };
235                                last if $last;
236                            }
237                            push @$actionLists, $actionList;
238                            $actions{$offset} = $#$actionLists;
239                        }
240                        $_->{'actions'} = $actions{$offset};
241                    }
242                }
243
244                $subtable->{'componentTable'} = $componentTable;
245                my $components = [unpack("n*", AAT_read_subtable($fh, $stateTableStart, $componentTable, $limits))];
246                foreach (@$components) {
247                    $_ = ($_ - $ligatureTable) . " +" if $_ >= $ligatureTable;
248                }
249                $subtable->{'components'} = $components;
250
251                $subtable->{'ligatureTable'} = $ligatureTable;
252                $subtable->{'ligatures'} = [unpack("n*", AAT_read_subtable($fh, $stateTableStart, $ligatureTable, $limits))];
253
254                $subtable->{'classes'} = $classes;
255                $subtable->{'states'} = $states;
256                $subtable->{'actionLists'} = $actionLists;
257            }
258
259            elsif ($type == 4) {    # non-contextual
260                my ($format, $lookup) = AAT_read_lookup($fh, 2, $length - 8, undef);
261                $subtable->{'format'} = $format;
262                $subtable->{'lookup'} = $lookup;
263            }
264
265            elsif ($type == 5) {    # insertion
266                my $stateTableStart = $fh->tell();
267                my ($classes, $states, $entries) = AAT_read_state_table($fh, 2);
268
269                my %insertListHash;
270                my $insertLists;
271                foreach (@$entries) {
272                    my $flags = $_->{'flags'};
273                    my @insertCount = (($flags & 0x03e0) >> 5, ($flags & 0x001f));
274                    my $actions = $_->{'actions'};
275                    foreach (0 .. 1) {
276                        if ($insertCount[$_] > 0) {
277                            $fh->seek($stateTableStart + $actions->[$_], IO::File::SEEK_SET);
278                            $fh->read($dat, $insertCount[$_] * 2);
279                            if (not defined $insertListHash{$dat}) {
280                                push @$insertLists, [unpack("n*", $dat)];
281                                $insertListHash{$dat} = $#$insertLists;
282                            }
283                            $actions->[$_] = $insertListHash{$dat};
284                        }
285                        else {
286                            $actions->[$_] = undef;
287                        }
288                    }
289                }
290
291                $subtable->{'classes'} = $classes;
292                $subtable->{'states'} = $states;
293                $subtable->{'insertLists'} = $insertLists;
294            }
295
296            else {
297                die "unknown subtable type";
298            }
299
300            push @$subtables, $subtable;
301            $fh->seek($subtableStart + $length, IO::File::SEEK_SET);
302        }
303
304        push @$chains,    {
305                            'defaultFlags'        => $defaultFlags,
306                            'featureEntries'    => $featureEntries,
307                            'subtables'            => $subtables
308                        };
309        $fh->seek($chainStart + $chainLength, IO::File::SEEK_SET);
310    }
311
312    $self->{'chains'} = $chains;
313
314    $self;
315}
316
317=head2 $t->out($fh)
318
319Writes the table to a file either from memory or by copying
320
321=cut
322
323sub out
324{
325    my ($self, $fh) = @_;
326
327    return $self->SUPER::out($fh) unless $self->{' read'};
328
329    my $chains = $self->{'chains'};
330    $fh->print(TTF_Pack("fL", $self->{'version'}, scalar @$chains));
331
332    foreach (@$chains) {
333        my $chainStart = $fh->tell();
334        my ($featureEntries, $subtables) = ($_->{'featureEntries'}, $_->{'subtables'});
335        $fh->print(TTF_Pack("LLSS", $_->{'defaultFlags'}, 0, scalar @$featureEntries, scalar @$subtables)); # placeholder for length
336
337        foreach (@$featureEntries) {
338            $fh->print(TTF_Pack("SSLL", $_->{'type'}, $_->{'setting'}, $_->{'enable'}, $_->{'disable'}));
339        }
340
341        foreach (@$subtables) {
342            my $subtableStart = $fh->tell();
343            my $type = $_->{'type'};
344            my $coverage = $type;
345            $coverage += 0x4000 if $_->{'direction'} eq 'RL';
346            $coverage += 0x2000 if $_->{'orientation'} eq 'VH';
347            $coverage += 0x8000 if $_->{'orientation'} eq 'V';
348
349            $fh->print(TTF_Pack("SSL", 0, $coverage, $_->{'subFeatureFlags'}));    # placeholder for length
350
351            if ($type == 0) {    # rearrangement
352                AAT_write_state_table($fh, $_->{'classes'}, $_->{'states'}, 0);
353            }
354
355            elsif ($type == 1) {    # contextual
356                my $stHeader = $fh->tell();
357                $fh->print(pack("nnnnn", (0) x 5));    # placeholders for stateSize, classTable, stateArray, entryTable, mappingTables
358
359                my $classTable = $fh->tell() - $stHeader;
360                my $classes = $_->{'classes'};
361                AAT_write_classes($fh, $classes);
362
363                my $stateArray = $fh->tell() - $stHeader;
364                my $states = $_->{'states'};
365                my ($stateSize, $entries) = AAT_write_states($fh, $classes, $stateArray, $states,
366                        sub {
367                            my $actions = $_->{'actions'};
368                            ( $_->{'flags'}, @$actions )
369                        }
370                    );
371
372                my $entryTable = $fh->tell() - $stHeader;
373                my $offset = ($entryTable + 8 * @$entries) / 2;
374                foreach (@$entries) {
375                    my ($nextState, $flags, @parts) = split /,/;
376                    $fh->print(pack("nnnn", $nextState, $flags, map { $_ eq "" ? 0 : $_ + $offset } @parts));
377                }
378
379                my $mappingTables = $fh->tell() - $stHeader;
380                my $mappings = $_->{'mappings'};
381                $fh->print(pack("n*", @$mappings));
382
383                my $loc = $fh->tell();
384                $fh->seek($stHeader, IO::File::SEEK_SET);
385                $fh->print(pack("nnnnn", $stateSize, $classTable, $stateArray, $entryTable, $mappingTables));
386                $fh->seek($loc, IO::File::SEEK_SET);
387            }
388
389            elsif ($type == 2) {    # ligature
390                my $stHeader = $fh->tell();
391                $fh->print(pack("nnnnnnn", (0) x 7));    # placeholders for stateSize, classTable, stateArray, entryTable, actionLists, components, ligatures
392
393                my $classTable = $fh->tell() - $stHeader;
394                my $classes = $_->{'classes'};
395                AAT_write_classes($fh, $classes);
396
397                my $stateArray = $fh->tell() - $stHeader;
398                my $states = $_->{'states'};
399
400                my ($stateSize, $entries) = AAT_write_states($fh, $classes, $stateArray, $states,
401                        sub {
402                            ( $_->{'flags'} & 0xc000, $_->{'actions'} )
403                        }
404                    );
405
406                my $actionLists = $_->{'actionLists'};
407                my %actionListOffset;
408                my $actionListDataLength = 0;
409                my @actionListEntries;
410                foreach (0 .. $#$entries) {
411                    my ($nextState, $flags, $offset) = split(/,/, $entries->[$_]);
412                    if ($offset eq "") {
413                        $offset = undef;
414                    }
415                    else {
416                        if (defined $actionListOffset{$offset}) {
417                            $offset = $actionListOffset{$offset};
418                        }
419                        else {
420                            $actionListOffset{$offset} = $actionListDataLength;
421                            my $list = $actionLists->[$offset];
422                            $actionListDataLength += 4 * @$list;
423                            push @actionListEntries, $list;
424                            $offset = $actionListOffset{$offset};
425                        }
426                    }
427                    $entries->[$_] = [ $nextState, $flags, $offset ];
428                }
429                my $entryTable = $fh->tell() - $stHeader;
430                my $ligActionLists = ($entryTable + @$entries * 4 + 3) & ~3;
431                foreach (@$entries) {
432                    $_->[2] += $ligActionLists if defined $_->[2];
433                    $fh->print(pack("nn", $_->[0], $_->[1] + $_->[2]));
434                }
435                $fh->print(pack("C*", (0) x ($ligActionLists - $entryTable - @$entries * 4)));
436
437                die "internal error" if $fh->tell() != $ligActionLists + $stHeader;
438
439                my $componentTable = $fh->tell() - $stHeader + $actionListDataLength;
440                my $actionList;
441                foreach $actionList (@actionListEntries) {
442                    foreach (0 .. $#$actionList) {
443                        my $action = $actionList->[$_];
444                        my $val = $action->{'component'} + $componentTable / 2;
445                        $val += 0x40000000 if $val < 0;
446                        $val &= 0x3fffffff;
447                        $val |= 0x40000000 if $action->{'store'};
448                        $val |= 0x80000000 if $_ == $#$actionList;
449                        $fh->print(pack("N", $val));
450                    }
451                }
452
453                die "internal error" if $fh->tell() != $componentTable + $stHeader;
454
455                my $components = $_->{'components'};
456                my $ligatureTable = $componentTable + @$components * 2;
457                $fh->print(pack("n*", map { (index($_, '+') >= 0 ? $ligatureTable : 0) + $_ } @$components));
458
459                my $ligatures = $_->{'ligatures'};
460                $fh->print(pack("n*", @$ligatures));
461
462                my $loc = $fh->tell();
463                $fh->seek($stHeader, IO::File::SEEK_SET);
464                $fh->print(pack("nnnnnnn", $stateSize, $classTable, $stateArray, $entryTable, $ligActionLists, $componentTable, $ligatureTable));
465                $fh->seek($loc, IO::File::SEEK_SET);
466            }
467
468            elsif ($type == 4) {    # non-contextual
469                AAT_write_lookup($fh, $_->{'format'}, $_->{'lookup'}, 2, undef);
470            }
471
472            elsif ($type == 5) {    # insertion
473            }
474
475            else {
476                die "unknown subtable type";
477            }
478
479            my $length = $fh->tell() - $subtableStart;
480            my $padBytes = (4 - ($length & 3)) & 3;
481            $fh->print(pack("C*", (0) x $padBytes));
482            $length += $padBytes;
483            $fh->seek($subtableStart, IO::File::SEEK_SET);
484            $fh->print(pack("n", $length));
485            $fh->seek($subtableStart + $length, IO::File::SEEK_SET);
486        }
487
488        my $chainLength = $fh->tell() - $chainStart;
489        $fh->seek($chainStart + 4, IO::File::SEEK_SET);
490        $fh->print(pack("N", $chainLength));
491        $fh->seek($chainStart + $chainLength, IO::File::SEEK_SET);
492    }
493}
494
495=head2 $t->print($fh)
496
497Prints a human-readable representation of the table
498
499=cut
500
501sub print
502{
503    my ($self, $fh) = @_;
504
505    $self->read;
506    my $feat = $self->{' PARENT'}->{'feat'};
507    $feat->read;
508    my $post = $self->{' PARENT'}->{'post'};
509    $post->read;
510
511    $fh = 'STDOUT' unless defined $fh;
512
513    $fh->printf("version %f\n", $self->{'version'});
514
515    my $chains = $self->{'chains'};
516    foreach (@$chains) {
517        my $defaultFlags = $_->{'defaultFlags'};
518        $fh->printf("chain: defaultFlags = %08x\n", $defaultFlags);
519
520        my $featureEntries = $_->{'featureEntries'};
521        foreach (@$featureEntries) {
522            $fh->printf("\tfeature %d, setting %d : enableFlags = %08x, disableFlags = %08x # '%s: %s'\n",
523                        $_->{'type'}, $_->{'setting'}, $_->{'enable'}, $_->{'disable'},
524                        $feat->settingName($_->{'type'}, $_->{'setting'}));
525        }
526
527        my $subtables = $_->{'subtables'};
528        foreach (@$subtables) {
529            my $type = $_->{'type'};
530            my $subFeatureFlags = $_->{'subFeatureFlags'};
531            $fh->printf("\n\t%s table, %s, %s, subFeatureFlags = %08x # %s (%s)\n",
532                        subtable_type_($type), $_->{'direction'}, $_->{'orientation'}, $subFeatureFlags,
533                        "Default " . ((($subFeatureFlags & $defaultFlags) != 0) ? "On" : "Off"),
534                        join(", ",
535                            map {
536                                join(": ", $feat->settingName($_->{'type'}, $_->{'setting'}) )
537                            } grep { ($_->{'enable'} & $subFeatureFlags) != 0 } @$featureEntries
538                        ) );
539
540            if ($type == 0) {    # rearrangement
541                print_classes_($fh, $_, $post);
542
543                $fh->print("\n");
544                my $states = $_->{'states'};
545                my @verbs = (    "0", "Ax->xA", "xD->Dx", "AxD->DxA",
546                                "ABx->xAB", "ABx->xBA", "xCD->CDx", "xCD->DCx",
547                                "AxCD->CDxA", "AxCD->DCxA", "ABxD->DxAB", "ABxD->DxBA",
548                                "ABxCD->CDxAB", "ABxCD->CDxBA", "ABxCD->DCxAB", "ABxCD->DCxBA");
549                foreach (0 .. $#$states) {
550                    $fh->printf("\t\tState %d:", $_);
551                    my $state = $states->[$_];
552                    foreach (@$state) {
553                        my $flags;
554                        $flags .= "!" if ($_->{'flags'} & 0x4000);
555                        $flags .= "<" if ($_->{'flags'} & 0x8000);
556                        $flags .= ">" if ($_->{'flags'} & 0x2000);
557                        $fh->printf("\t(%s%d,%s)", $flags, $_->{'nextState'}, $verbs[($_->{'flags'} & 0x000f)]);
558                    }
559                    $fh->print("\n");
560                }
561            }
562
563            elsif ($type == 1) {    # contextual
564                print_classes_($fh, $_, $post);
565
566                $fh->print("\n");
567                my $states = $_->{'states'};
568                foreach (0 .. $#$states) {
569                    $fh->printf("\t\tState %d:", $_);
570                    my $state = $states->[$_];
571                    foreach (@$state) {
572                        my $flags;
573                        $flags .= "!" if ($_->{'flags'} & 0x4000);
574                        $flags .= "*" if ($_->{'flags'} & 0x8000);
575                        my $actions = $_->{'actions'};
576                        $fh->printf("\t(%s%d,%s,%s)", $flags, $_->{'nextState'}, map { defined $_ ? $_ : "=" } @$actions);
577                    }
578                    $fh->print("\n");
579                }
580
581                $fh->print("\n");
582                my $mappings = $_->{'mappings'};
583                foreach (0 .. $#$mappings) {
584                    $fh->printf("\t\tMapping %d: %d [%s]\n", $_, $mappings->[$_], $post->{'VAL'}[$mappings->[$_]]);
585                }
586            }
587
588            elsif ($type == 2) {    # ligature
589                print_classes_($fh, $_, $post);
590
591                $fh->print("\n");
592                my $states = $_->{'states'};
593                foreach (0 .. $#$states) {
594                    $fh->printf("\t\tState %d:", $_);
595                    my $state = $states->[$_];
596                    foreach (@$state) {
597                        my $flags;
598                        $flags .= "!" if ($_->{'flags'} & 0x4000);
599                        $flags .= "*" if ($_->{'flags'} & 0x8000);
600                        $fh->printf("\t(%s%d,%s)", $flags, $_->{'nextState'}, defined $_->{'actions'} ? $_->{'actions'} : "=");
601                    }
602                    $fh->print("\n");
603                }
604
605                $fh->print("\n");
606                my $actionLists = $_->{'actionLists'};
607                foreach (0 .. $#$actionLists) {
608                    $fh->printf("\t\tList %d:\t", $_);
609                    my $actionList = $actionLists->[$_];
610                    $fh->printf("%s\n", join(", ", map { ($_->{'component'} . ($_->{'store'} ? "*" : "") ) } @$actionList));
611                }
612
613                my $ligatureTable = $_->{'ligatureTable'};
614
615                $fh->print("\n");
616                my $components = $_->{'components'};
617                foreach (0 .. $#$components) {
618                    $fh->printf("\t\tComponent %d: %s\n", $_, $components->[$_]);
619                }
620
621                $fh->print("\n");
622                my $ligatures = $_->{'ligatures'};
623                foreach (0 .. $#$ligatures) {
624                    $fh->printf("\t\tLigature %d: %d [%s]\n", $_, $ligatures->[$_], $post->{'VAL'}[$ligatures->[$_]]);
625                }
626            }
627
628            elsif ($type == 4) {    # non-contextual
629                my $lookup = $_->{'lookup'};
630                $fh->printf("\t\tLookup format %d\n", $_->{'format'});
631                if (defined $lookup) {
632                    foreach (sort { $a <=> $b } keys %$lookup) {
633                        $fh->printf("\t\t\t%d [%s] -> %d [%s])\n", $_, $post->{'VAL'}[$_], $lookup->{$_}, $post->{'VAL'}[$lookup->{$_}]);
634                    }
635                }
636            }
637
638            elsif ($type == 5) {    # insertion
639                print_classes_($fh, $_, $post);
640
641                $fh->print("\n");
642                my $states = $_->{'states'};
643                foreach (0 .. $#$states) {
644                    $fh->printf("\t\tState %d:", $_);
645                    my $state = $states->[$_];
646                    foreach (@$state) {
647                        my $flags;
648                        $flags .= "!" if ($_->{'flags'} & 0x4000);
649                        $flags .= "*" if ($_->{'flags'} & 0x8000);
650                        my $actions = $_->{'actions'};
651                        $fh->printf("\t(%s%d,%s,%s)", $flags, $_->{'nextState'}, map { defined $_ ? $_ : "=" } @$actions);
652                    }
653                    $fh->print("\n");
654                }
655
656                $fh->print("\n");
657                my $insertLists = $_->{'insertLists'};
658                foreach (0 .. $#$insertLists) {
659                    my $insertList = $insertLists->[$_];
660                    $fh->printf("\t\tList %d: %s\n", $_, join(", ", map { $_ . " [" . $post->{'VAL'}[$_] . "]" } @$insertList));
661                }
662            }
663
664            else {
665                # unknown
666            }
667        }
668    }
669}
670
671sub print_classes_
672{
673    my ($fh, $subtable, $post) = @_;
674
675    my $classes = $subtable->{'classes'};
676    foreach (0 .. $#$classes) {
677        my $class = $classes->[$_];
678        if (defined $class) {
679            $fh->printf("\t\tClass %d:\t%s\n", $_, join(", ", map { $_ . " [" . $post->{'VAL'}[$_] . "]" } @$class));
680        }
681    }
682}
683
684sub subtable_type_
685{
686    my ($val) = @_;
687    my ($res);
688
689    my @types =    (
690                    'Rearrangement',
691                    'Contextual',
692                    'Ligature',
693                    undef,
694                    'Non-contextual',
695                    'Insertion',
696                );
697    $res = $types[$val] or ('Undefined (' . $val . ')');
698
699    $res;
700}
701
7021;
703
704=head1 BUGS
705
706None known
707
708=head1 AUTHOR
709
710Jonathan Kew L<http://scripts.sil.org/FontUtils>.
711
712
713=head1 LICENSING
714
715Copyright (c) 1998-2016, SIL International (http://www.sil.org)
716
717This module is released under the terms of the Artistic License 2.0.
718For details, see the full text of the license in the file LICENSE.
719
720
721
722=cut