PageRenderTime 52ms CodeModel.GetById 25ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/Font/TTF/GSUB.pm

http://github.com/gonzoua/book-tools
Perl | 246 lines | 185 code | 60 blank | 1 comment | 46 complexity | 7fcab62eea05590cee3cf22c6aeb3966 MD5 | raw file
  1. package Font::TTF::GSUB;
  2. =head1 NAME
  3. Font::TTF::GSUB - Module support for the GSUB table in conjunction with TTOpen
  4. =head1 DESCRIPTION
  5. Handles the GSUB subtables in relation to Ttopen tables. Due to the variety of
  6. different lookup types, the data structures are not all that straightforward,
  7. although I have tried to make life easy for myself when using this!
  8. =head1 INSTANCE VARIABLES
  9. The structure of a GSUB table is the same as that given in L<Font::TTF::Ttopen>.
  10. Here we give some of the semantics specific to GSUB lookups.
  11. =over 4
  12. =item ACTION_TYPE
  13. This is a string taking one of 4 values indicating the nature of the information
  14. in the ACTION array of the rule:
  15. =over 8
  16. =item g
  17. The action contains a string of glyphs to replace the match string by
  18. =item l
  19. The action array contains a list of lookups and offsets to run, in order, on
  20. the matched string
  21. =item a
  22. The action array is an unordered set of optional replacements for the matched
  23. glyph. The application should make the selection somehow.
  24. =item o
  25. The action array is empty (in fact there is no rule array for this type of
  26. rule) and the ADJUST value should be added to the glyph id to find the replacement
  27. glyph id value
  28. =back
  29. =item MATCH_TYPE
  30. This indicates which type of information the various MATCH arrays (MATCH, PRE,
  31. POST) hold in the rule:
  32. =over 8
  33. =item g
  34. The array holds a string of glyph ids which should match exactly
  35. =item c
  36. The array holds a sequence of class definitions which each glyph should
  37. correspondingly match to
  38. =item o
  39. The array holds offsets to coverage tables
  40. =back
  41. =back
  42. =head1 CORRESPONDANCE TO LAYOUT TYPES
  43. The following table gives the values for ACTION_TYPE and MATCH_TYPE for each
  44. of the 11 different lookup types found in the GSUB table definition I have:
  45. 1.1 1.2 2 3 4 5.1 5.2 5.3 6.1 6.2 6.3
  46. ACTION_TYPE o g g a g l l l l l l
  47. MATCH_TYPE g g c o g c o
  48. Hopefully, the rest of the uses of the variables should make sense from this
  49. table.
  50. =head1 METHODS
  51. =cut
  52. use strict;
  53. use vars qw(@ISA);
  54. use Font::TTF::Utils;
  55. use Font::TTF::Ttopen;
  56. @ISA = qw(Font::TTF::Ttopen);
  57. =head2 $t->read_sub($fh, $lookup, $index)
  58. Asked by the superclass to read in from the given file the indexth subtable from
  59. lookup number lookup. The file is positioned ready for the read.
  60. =cut
  61. sub read_sub
  62. {
  63. my ($self, $fh, $main_lookup, $sindex) = @_;
  64. my ($type) = $main_lookup->{'TYPE'};
  65. my ($loc) = $fh->tell();
  66. my ($lookup) = $main_lookup->{'SUB'}[$sindex];
  67. my ($dat, $s, @subst, $t, $fmt, $cover, $count, $mcount, $scount, $i, $gid);
  68. my (@srec);
  69. if ($type == 6)
  70. {
  71. $fh->read($dat, 4);
  72. ($fmt, $cover) = TTF_Unpack('S2', $dat);
  73. if ($fmt < 3)
  74. {
  75. $fh->read($dat, 2);
  76. $count = TTF_Unpack('S', $dat);
  77. }
  78. } else
  79. {
  80. $fh->read($dat, 6);
  81. ($fmt, $cover, $count) = TTF_Unpack("S3", $dat);
  82. }
  83. unless ($fmt == 3 && ($type == 5 || $type == 6))
  84. { $lookup->{'COVERAGE'} = $self->read_cover($cover, $loc, $lookup, $fh, 1); }
  85. $lookup->{'FORMAT'} = $fmt;
  86. if ($type == 1 && $fmt == 1)
  87. {
  88. $count -= 65536 if ($count > 32767);
  89. $lookup->{'ADJUST'} = $count;
  90. $lookup->{'ACTION_TYPE'} = 'o';
  91. } elsif ($type == 1 && $fmt == 2)
  92. {
  93. $fh->read($dat, $count << 1);
  94. @subst = TTF_Unpack('S*', $dat);
  95. foreach $s (@subst)
  96. { push(@{$lookup->{'RULES'}}, [{'ACTION' => [$s]}]); }
  97. $lookup->{'ACTION_TYPE'} = 'g';
  98. } elsif ($type == 2 || $type == 3)
  99. {
  100. $fh->read($dat, $count << 1); # number of offsets
  101. foreach $s (TTF_Unpack('S*', $dat))
  102. {
  103. $fh->seek($loc + $s, 0);
  104. $fh->read($dat, 2);
  105. $t = TTF_Unpack('S', $dat);
  106. $fh->read($dat, $t << 1);
  107. push(@{$lookup->{'RULES'}}, [{'ACTION' => [TTF_Unpack('S*', $dat)]}]);
  108. }
  109. $lookup->{'ACTION_TYPE'} = ($type == 2 ? 'g' : 'a');
  110. } elsif ($type == 4)
  111. {
  112. $fh->read($dat, $count << 1);
  113. foreach $s (TTF_Unpack('S*', $dat))
  114. {
  115. @subst = ();
  116. $fh->seek($loc + $s, 0);
  117. $fh->read($dat, 2);
  118. $t = TTF_Unpack('S', $dat);
  119. $fh->read($dat, $t << 1);
  120. foreach $t (TTF_Unpack('S*', $dat))
  121. {
  122. $fh->seek($loc + $s + $t, 0);
  123. $fh->read($dat, 4);
  124. ($gid, $mcount) = TTF_Unpack('S2', $dat);
  125. $fh->read($dat, ($mcount - 1) << 1);
  126. push(@subst, {'ACTION' => [$gid], 'MATCH' => [TTF_Unpack('S*', $dat)]});
  127. }
  128. push(@{$lookup->{'RULES'}}, [@subst]);
  129. }
  130. $lookup->{'ACTION_TYPE'} = 'g';
  131. $lookup->{'MATCH_TYPE'} = 'g';
  132. } elsif ($type == 5 || $type == 6)
  133. { $self->read_context($lookup, $fh, $type, $fmt, $cover, $count, $loc); }
  134. $lookup;
  135. }
  136. =head2 $t->extension
  137. Returns the table type number for the extension table
  138. =cut
  139. sub extension
  140. { return 7; }
  141. =head2 $t->out_sub($fh, $lookup, $index)
  142. Passed the filehandle to output to, suitably positioned, the lookup and subtable
  143. index, this function outputs the subtable to $fh at that point.
  144. =cut
  145. sub out_sub
  146. {
  147. my ($self, $fh, $main_lookup, $index, $ctables, $base) = @_;
  148. my ($type) = $main_lookup->{'TYPE'};
  149. my ($lookup) = $main_lookup->{'SUB'}[$index];
  150. my ($fmt) = $lookup->{'FORMAT'};
  151. my ($out, $r, $t, $i, $j, $offc, $offd, $numd);
  152. my ($num) = $#{$lookup->{'RULES'}} + 1;
  153. if ($type == 1)
  154. {
  155. $out = pack("nn", $fmt, Font::TTF::Ttopen::ref_cache($lookup->{'COVERAGE'}, $ctables, 2 + $base));
  156. if ($fmt == 1)
  157. { $out .= pack("n", $lookup->{'ADJUST'}); }
  158. else
  159. {
  160. $out .= pack("n", $num);
  161. foreach $r (@{$lookup->{'RULES'}})
  162. { $out .= pack("n", $r->[0]{'ACTION'}[0]); }
  163. }
  164. } elsif ($type == 2 || $type == 3)
  165. {
  166. $out = pack("nnn", $fmt, Font::TTF::Ttopen::ref_cache($lookup->{'COVERAGE'}, $ctables, 2 + $base),
  167. $num);
  168. $out .= pack('n*', (0) x $num);
  169. $offc = length($out);
  170. for ($i = 0; $i < $num; $i++)
  171. {
  172. $out .= pack("n*", $#{$lookup->{'RULES'}[$i][0]{'ACTION'}} + 1,
  173. @{$lookup->{'RULES'}[$i][0]{'ACTION'}});
  174. substr($out, ($i << 1) + 6, 2) = pack('n', $offc);
  175. $offc = length($out);
  176. }
  177. } elsif ($type == 4 || $type == 5 || $type == 6)
  178. { $out = $self->out_context($lookup, $fh, $type, $fmt, $ctables, $out, $num, $base); }
  179. # Font::TTF::Ttopen::out_final($fh, $out, [[$ctables, 0]]);
  180. $out;
  181. }
  182. =head1 AUTHOR
  183. Martin Hosken Martin_Hosken@sil.org. See L<Font::TTF::Font> for copyright and
  184. licensing.
  185. =cut
  186. 1;