ttfunk 1.7.0 → 1.8.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/CHANGELOG.md +74 -0
  4. data/README.md +17 -15
  5. data/lib/ttfunk/aggregate.rb +5 -0
  6. data/lib/ttfunk/bin_utils.rb +27 -8
  7. data/lib/ttfunk/bit_field.rb +25 -2
  8. data/lib/ttfunk/collection.rb +27 -3
  9. data/lib/ttfunk/directory.rb +7 -1
  10. data/lib/ttfunk/encoded_string.rb +58 -4
  11. data/lib/ttfunk/max.rb +14 -0
  12. data/lib/ttfunk/min.rb +14 -0
  13. data/lib/ttfunk/one_based_array.rb +20 -0
  14. data/lib/ttfunk/otf_encoder.rb +5 -14
  15. data/lib/ttfunk/placeholder.rb +15 -1
  16. data/lib/ttfunk/reader.rb +6 -4
  17. data/lib/ttfunk/resource_file.rb +29 -5
  18. data/lib/ttfunk/sci_form.rb +20 -3
  19. data/lib/ttfunk/sub_table.rb +29 -4
  20. data/lib/ttfunk/subset/base.rb +48 -0
  21. data/lib/ttfunk/subset/code_page.rb +49 -2
  22. data/lib/ttfunk/subset/mac_roman.rb +2 -0
  23. data/lib/ttfunk/subset/unicode.rb +32 -0
  24. data/lib/ttfunk/subset/unicode_8bit.rb +32 -0
  25. data/lib/ttfunk/subset/windows_1252.rb +2 -0
  26. data/lib/ttfunk/subset.rb +8 -0
  27. data/lib/ttfunk/subset_collection.rb +39 -14
  28. data/lib/ttfunk/sum.rb +13 -0
  29. data/lib/ttfunk/table/cff/charset.rb +96 -18
  30. data/lib/ttfunk/table/cff/charsets/expert.rb +3 -2
  31. data/lib/ttfunk/table/cff/charsets/expert_subset.rb +3 -2
  32. data/lib/ttfunk/table/cff/charsets/iso_adobe.rb +3 -2
  33. data/lib/ttfunk/table/cff/charsets/standard_strings.rb +3 -2
  34. data/lib/ttfunk/table/cff/charsets.rb +1 -0
  35. data/lib/ttfunk/table/cff/charstring.rb +33 -12
  36. data/lib/ttfunk/table/cff/charstrings_index.rb +17 -11
  37. data/lib/ttfunk/table/cff/dict.rb +53 -23
  38. data/lib/ttfunk/table/cff/encoding.rb +82 -24
  39. data/lib/ttfunk/table/cff/encodings/expert.rb +3 -2
  40. data/lib/ttfunk/table/cff/encodings/standard.rb +3 -2
  41. data/lib/ttfunk/table/cff/encodings.rb +1 -0
  42. data/lib/ttfunk/table/cff/fd_selector.rb +61 -21
  43. data/lib/ttfunk/table/cff/font_dict.rb +30 -18
  44. data/lib/ttfunk/table/cff/font_index.rb +22 -10
  45. data/lib/ttfunk/table/cff/header.rb +16 -3
  46. data/lib/ttfunk/table/cff/index.rb +97 -65
  47. data/lib/ttfunk/table/cff/one_based_index.rb +11 -1
  48. data/lib/ttfunk/table/cff/path.rb +43 -4
  49. data/lib/ttfunk/table/cff/private_dict.rb +31 -11
  50. data/lib/ttfunk/table/cff/subr_index.rb +7 -2
  51. data/lib/ttfunk/table/cff/top_dict.rb +82 -59
  52. data/lib/ttfunk/table/cff/top_index.rb +10 -6
  53. data/lib/ttfunk/table/cff.rb +41 -21
  54. data/lib/ttfunk/table/cmap/format00.rb +27 -6
  55. data/lib/ttfunk/table/cmap/format04.rb +34 -14
  56. data/lib/ttfunk/table/cmap/format06.rb +28 -1
  57. data/lib/ttfunk/table/cmap/format10.rb +29 -2
  58. data/lib/ttfunk/table/cmap/format12.rb +29 -2
  59. data/lib/ttfunk/table/cmap/subtable.rb +50 -6
  60. data/lib/ttfunk/table/cmap.rb +21 -0
  61. data/lib/ttfunk/table/dsig.rb +47 -6
  62. data/lib/ttfunk/table/glyf/compound.rb +73 -6
  63. data/lib/ttfunk/table/glyf/path_based.rb +40 -3
  64. data/lib/ttfunk/table/glyf/simple.rb +50 -5
  65. data/lib/ttfunk/table/glyf.rb +15 -7
  66. data/lib/ttfunk/table/head.rb +84 -6
  67. data/lib/ttfunk/table/hhea.rb +71 -10
  68. data/lib/ttfunk/table/hmtx.rb +32 -5
  69. data/lib/ttfunk/table/kern/format0.rb +25 -7
  70. data/lib/ttfunk/table/kern.rb +16 -4
  71. data/lib/ttfunk/table/loca.rb +21 -8
  72. data/lib/ttfunk/table/maxp.rb +195 -10
  73. data/lib/ttfunk/table/name.rb +126 -9
  74. data/lib/ttfunk/table/os2.rb +150 -26
  75. data/lib/ttfunk/table/post/format10.rb +7 -0
  76. data/lib/ttfunk/table/post/format20.rb +9 -0
  77. data/lib/ttfunk/table/post/format30.rb +6 -0
  78. data/lib/ttfunk/table/post/format40.rb +5 -0
  79. data/lib/ttfunk/table/post.rb +63 -7
  80. data/lib/ttfunk/table/sbix.rb +50 -14
  81. data/lib/ttfunk/table/simple.rb +5 -0
  82. data/lib/ttfunk/table/vorg.rb +31 -3
  83. data/lib/ttfunk/table.rb +20 -1
  84. data/lib/ttfunk/ttf_encoder.rb +39 -41
  85. data/lib/ttfunk.rb +154 -1
  86. data.tar.gz.sig +0 -0
  87. metadata +50 -28
  88. metadata.gz.sig +0 -0
@@ -3,10 +3,30 @@
3
3
  module TTFunk
4
4
  class Table
5
5
  class Cmap
6
+ # Format 12: Segmented coverage.
7
+ #
8
+ # This module conditionally extends {TTFunk::Table::Cmap::Subtable}.
6
9
  module Format12
10
+ # Language.
11
+ # @return [Integer]
7
12
  attr_reader :language
13
+
14
+ # Code map.
15
+ # @return [Hash{Integer => Integer}]
8
16
  attr_reader :code_map
9
17
 
18
+ # Encode the encoding record to format 12.
19
+ #
20
+ # @param charmap [Hash{Integer => Integer}] a hash mapping character
21
+ # codes to glyph IDs from the original font.
22
+ # @return [Hash]
23
+ # * `:charmap` (<tt>Hash{Integer => Hash}</tt>) keys are the characrers in
24
+ # `charset`, values are hashes:
25
+ # * `:old` (<tt>Integer</tt>) - glyph ID in the original font.
26
+ # * `:new` (<tt>Integer</tt>) - glyph ID in the subset font.
27
+ # that maps the characters in charmap to a
28
+ # * `:subtable` (<tt>String</tt>) - serialized encoding record.
29
+ # * `:max_glyph_id` (<tt>Integer</tt>) - maximum glyph ID in the new font.
10
30
  def self.encode(charmap)
11
31
  next_id = 0
12
32
  glyph_map = { 0 => 0 }
@@ -32,23 +52,30 @@ module TTFunk
32
52
  end
33
53
 
34
54
  subtable = [
35
- 12, 0, 16 + 12 * range_lengths.size, 0, range_lengths.size
55
+ 12, 0, 16 + (12 * range_lengths.size), 0, range_lengths.size,
36
56
  ].pack('nnNNN')
37
57
  range_lengths.each_with_index do |length, i|
38
58
  firstglyph = range_firstglyphs[i]
39
59
  firstcode = range_firstcodes[i]
40
60
  subtable << [
41
- firstcode, firstcode + length - 1, firstglyph
61
+ firstcode, firstcode + length - 1, firstglyph,
42
62
  ].pack('NNN')
43
63
  end
44
64
 
45
65
  { charmap: new_map, subtable: subtable, max_glyph_id: next_id + 1 }
46
66
  end
47
67
 
68
+ # Get glyph ID for character code.
69
+ #
70
+ # @param code [Integer] character code.
71
+ # @return [Integer] glyph ID.
48
72
  def [](code)
49
73
  @code_map[code] || 0
50
74
  end
51
75
 
76
+ # Is this encoding record format supported?
77
+ #
78
+ # @return [true]
52
79
  def supported?
53
80
  true
54
81
  end
@@ -5,21 +5,54 @@ require_relative '../../reader'
5
5
  module TTFunk
6
6
  class Table
7
7
  class Cmap
8
+ # Character to Glyph Index encoding record.
9
+ # This class can be extended with a format-specific
10
+ #
11
+ # @see TTFunk::Table::Cmap::Format00
12
+ # @see TTFunk::Table::Cmap::Format04
13
+ # @see TTFunk::Table::Cmap::Format06
14
+ # @see TTFunk::Table::Cmap::Format10
15
+ # @see TTFunk::Table::Cmap::Format12
8
16
  class Subtable
9
17
  include Reader
10
18
 
19
+ # Platform ID.
20
+ # @return [Integer]
11
21
  attr_reader :platform_id
22
+
23
+ # Platform-specific encoding ID.
24
+ # @return [Integere]
12
25
  attr_reader :encoding_id
26
+
27
+ # Record encoding format.
28
+ # @return [Integer]
13
29
  attr_reader :format
14
30
 
31
+ # Most used encoding mappings.
15
32
  ENCODING_MAPPINGS = {
16
33
  mac_roman: { platform_id: 1, encoding_id: 0 }.freeze,
17
34
  # Use microsoft unicode, instead of generic unicode, for optimal
18
35
  # Windows support
19
36
  unicode: { platform_id: 3, encoding_id: 1 }.freeze,
20
- unicode_ucs4: { platform_id: 3, encoding_id: 10 }.freeze
37
+ unicode_ucs4: { platform_id: 3, encoding_id: 10 }.freeze,
21
38
  }.freeze
22
39
 
40
+ # Encode encoding record.
41
+ #
42
+ # @param charmap [Hash{Integer => Integer}] keys are code points in the
43
+ # used encoding, values are Unicode code points.
44
+ # @param encoding [Symbol] - one of the encodign mapping in
45
+ # {ENCODING_MAPPINGS}
46
+ # @return [Hash]
47
+ # * `:platform_id` (<tt>Integer</tt>) - Platform ID of this encoding record.
48
+ # * `:encoding_id` (<tt>Integer</tt>) - Encodign ID of this encoding record.
49
+ # * `:subtable` (<tt>String</tt>) - encoded encoding record.
50
+ # * `:max_glyph_id` (<tt>Integer</tt>) - maximum glyph ID in this encoding
51
+ # record.
52
+ # * `:charmap` (<tt>Hash{Integer => Hash}</tt>) - keys are codepoints in this
53
+ # encoding record, values are hashes:
54
+ # * `:new` - new glyph ID.
55
+ # * `:old` - glyph ID in the original font.
23
56
  def self.encode(charmap, encoding)
24
57
  case encoding
25
58
  when :mac_roman
@@ -43,11 +76,13 @@ module TTFunk
43
76
  mapping[:platform_id],
44
77
  mapping[:encoding_id],
45
78
  12,
46
- result[:subtable]
47
- ].pack('nnNA*')
79
+ result[:subtable],
80
+ ].pack('nnNA*'),
48
81
  )
49
82
  end
50
83
 
84
+ # @param file [TTFunk::File]
85
+ # @param table_start [Integer]
51
86
  def initialize(file, table_start)
52
87
  @file = file
53
88
  @platform_id, @encoding_id, @offset = read(8, 'nnN')
@@ -68,16 +103,25 @@ module TTFunk
68
103
  end
69
104
  end
70
105
 
106
+ # Is this an encoding record for Unicode?
107
+ #
108
+ # @return [Boolean]
71
109
  def unicode?
72
- platform_id == 3 && (encoding_id == 1 || encoding_id == 10) &&
73
- format != 0 ||
74
- platform_id.zero? && format != 0
110
+ (platform_id == 3 && (encoding_id == 1 || encoding_id == 10) && format != 0) ||
111
+ (platform_id.zero? && format != 0)
75
112
  end
76
113
 
114
+ # Is this encoding record format supported?
115
+ #
116
+ # @return [Boolean]
77
117
  def supported?
78
118
  false
79
119
  end
80
120
 
121
+ # Get glyph ID for character code.
122
+ #
123
+ # @param _code [Integer] character code.
124
+ # @return [Integer] glyph ID.
81
125
  def [](_code)
82
126
  raise NotImplementedError, "cmap format #{@format} is not supported"
83
127
  end
@@ -2,10 +2,28 @@
2
2
 
3
3
  module TTFunk
4
4
  class Table
5
+ # Character to Glyph Index Mapping (`cmap`) table.
5
6
  class Cmap < Table
7
+ # Table version.
8
+ # @return [Integer]
6
9
  attr_reader :version
10
+
11
+ # Encoding tables.
12
+ # @return [Array<TTFunk::Table::Cmap::Subtable>]
7
13
  attr_reader :tables
8
14
 
15
+ # Encode table.
16
+ #
17
+ # @param charmap [Hash{Integer => Integer}]
18
+ # @param encoding [Symbol]
19
+ # @return [Hash]
20
+ # * `:charmap` (<tt>Hash{Integer => Hash}</tt>) keys are the characrers in
21
+ # `charset`, values are hashes:
22
+ # * `:old` (<tt>Integer</tt>) - glyph ID in the original font.
23
+ # * `:new` (<tt>Integer</tt>) - glyph ID in the subset font.
24
+ # that maps the characters in charmap to a
25
+ # * `:table` (<tt>String</tt>) - serialized table.
26
+ # * `:max_glyph_id` (<tt>Integer</tt>) - maximum glyph ID in the new font.
9
27
  def self.encode(charmap, encoding)
10
28
  result = Cmap::Subtable.encode(charmap, encoding)
11
29
 
@@ -14,6 +32,9 @@ module TTFunk
14
32
  result
15
33
  end
16
34
 
35
+ # Get Unicode encoding records.
36
+ #
37
+ # @return [Array<TTFunk::Table::Cmap::Subtable>]
17
38
  def unicode
18
39
  # Because most callers just call .first on the result, put tables with
19
40
  # highest-number format first. Unsupported formats will be ignored.
@@ -2,10 +2,30 @@
2
2
 
3
3
  module TTFunk
4
4
  class Table
5
+ # Digital Signature (`DSIG`) table.
5
6
  class Dsig < Table
7
+ # Signature record.
6
8
  class SignatureRecord
7
- attr_reader :format, :length, :offset, :signature
9
+ # Format of the signature.
10
+ # @return [Integer]
11
+ attr_reader :format
8
12
 
13
+ # Length of signature in bytes.
14
+ # @return [Integer]
15
+ attr_reader :length
16
+
17
+ # Offset to the signature block from the beginning of the table.
18
+ # @return [Integer]
19
+ attr_reader :offset
20
+
21
+ # Signature PKCS#7 packet.
22
+ # @return [String]
23
+ attr_reader :signature
24
+
25
+ # @param format [Integer]
26
+ # @param length [Integer]
27
+ # @param offset [Integer]
28
+ # @param signature [String]
9
29
  def initialize(format, length, offset, signature)
10
30
  @format = format
11
31
  @length = length
@@ -14,10 +34,28 @@ module TTFunk
14
34
  end
15
35
  end
16
36
 
17
- attr_reader :version, :flags, :signatures
37
+ # Version umber of this table.
38
+ # @return [Integer]
39
+ attr_reader :version
40
+
41
+ # Permission flags.
42
+ # @return [Integer]
43
+ attr_reader :flags
44
+
45
+ # Signature records.
46
+ # @return [Array<SignatureRecord>]
47
+ attr_reader :signatures
18
48
 
49
+ # Table tag.
19
50
  TAG = 'DSIG'
20
51
 
52
+ # Encode table.
53
+ #
54
+ # **Note**: all signatures will be lost. This encodes an empty table
55
+ # regardless whether the supplied table contains any signtaures or not.
56
+ #
57
+ # @param dsig [TTFunk::Table::Dsig]
58
+ # @return [String]
21
59
  def self.encode(dsig)
22
60
  return unless dsig
23
61
 
@@ -26,6 +64,9 @@ module TTFunk
26
64
  [dsig.version, 0, 0].pack('Nnn')
27
65
  end
28
66
 
67
+ # Table tag.
68
+ #
69
+ # @return [String]
29
70
  def tag
30
71
  TAG
31
72
  end
@@ -36,16 +77,16 @@ module TTFunk
36
77
  @version, num_signatures, @flags = read(8, 'Nnn')
37
78
 
38
79
  @signatures =
39
- Array.new(num_signatures) do
80
+ Array.new(num_signatures) {
40
81
  format, length, sig_offset = read(12, 'N3')
41
82
  signature =
42
- parse_from(offset + sig_offset) do
83
+ parse_from(offset + sig_offset) {
43
84
  _, _, sig_length = read(8, 'nnN')
44
85
  read(sig_length, 'C*')
45
- end
86
+ }
46
87
 
47
88
  SignatureRecord.new(format, length, sig_offset, signature)
48
- end
89
+ }
49
90
  end
50
91
  end
51
92
  end
@@ -5,32 +5,92 @@ require_relative '../../reader'
5
5
  module TTFunk
6
6
  class Table
7
7
  class Glyf
8
+ # Composite TrueType glyph.
8
9
  class Compound
9
10
  include Reader
10
11
 
12
+ # Flags bit 0: arg1 and arg2 are words.
11
13
  ARG_1_AND_2_ARE_WORDS = 0x0001
14
+
15
+ # Flags bit 3: there is a simple scale for the component.
12
16
  WE_HAVE_A_SCALE = 0x0008
17
+
18
+ # Flags bit 5: at least one more glyph after this one.
13
19
  MORE_COMPONENTS = 0x0020
20
+
21
+ # Flags bit 6: the x direction will use a different scale from the
22
+ # y direction.
14
23
  WE_HAVE_AN_X_AND_Y_SCALE = 0x0040
24
+
25
+ # Flags bit 7: there is a 2 by 2 transformation that will be used to
26
+ # scale the component.
15
27
  WE_HAVE_A_TWO_BY_TWO = 0x0080
28
+
29
+ # Flags bit 8: following the last component are instructions for the
30
+ # composite character.
16
31
  WE_HAVE_INSTRUCTIONS = 0x0100
17
32
 
18
- attr_reader :id, :raw
33
+ # Glyph ID.
34
+ # @return [Integer]
35
+ attr_reader :id
36
+
37
+ # Binary serialization of this glyph.
38
+ # @return [String]
39
+ attr_reader :raw
40
+
41
+ # Number of contours in this glyph.
42
+ # @return [Integer]
19
43
  attr_reader :number_of_contours
20
- attr_reader :x_min, :y_min, :x_max, :y_max
44
+
45
+ # Minimum x for coordinate.
46
+ # @return [Integer]
47
+ attr_reader :x_min
48
+
49
+ # Minimum y for coordinate.
50
+ # @return [Integer]
51
+ attr_reader :y_min
52
+
53
+ # Maximum x for coordinate.
54
+ # @return [Integer]
55
+ attr_reader :x_max
56
+
57
+ # Maximum y for coordinate.
58
+ # @return [Integer]
59
+ attr_reader :y_max
60
+
61
+ # IDs of compound glyphs.
21
62
  attr_reader :glyph_ids
22
63
 
64
+ # Component glyph.
65
+ #
66
+ # @!attribute [rw] flags
67
+ # Component flag.
68
+ # @return [Integer]
69
+ # @!attribute [rw] glyph_index
70
+ # Glyph index of component.
71
+ # @return [Integer]
72
+ # @!attribute [rw] arg1
73
+ # x-offset for component or point number.
74
+ # @return [Integer]
75
+ # @!attribute [rw] arg2
76
+ # y-offset for component or point number.
77
+ # @return [Integer]
78
+ # @!attribute [rw] transform
79
+ # Transformation.
80
+ # @return []
23
81
  Component = Struct.new(:flags, :glyph_index, :arg1, :arg2, :transform)
24
82
 
83
+ # @param id [Integer] glyph ID.
84
+ # @param raw [String]
25
85
  def initialize(id, raw)
26
86
  @id = id
27
87
  @raw = raw
28
88
  io = StringIO.new(raw)
29
89
 
30
90
  @number_of_contours, @x_min, @y_min, @x_max, @y_max =
31
- io.read(10).unpack('n*').map do |i|
91
+ io.read(10).unpack('n*').map { |i|
32
92
  BinUtils.twos_comp_to_int(i, bit_width: 16)
33
- end
93
+ }
34
94
 
35
95
  # Because TTFunk only cares about glyphs insofar as they (1) provide
36
96
  # a bounding box for each glyph, and (2) can be rewritten into a
@@ -48,9 +108,9 @@ module TTFunk
48
108
  loop do
49
109
  flags, glyph_id = @raw[offset, 4].unpack('n*')
50
110
  @glyph_ids << glyph_id
51
- @glyph_id_offsets << offset + 2
111
+ @glyph_id_offsets << (offset + 2)
52
112
 
53
- break unless flags & MORE_COMPONENTS != 0
113
+ break if (flags & MORE_COMPONENTS).zero?
54
114
 
55
115
  offset += 4
56
116
 
@@ -71,10 +131,17 @@ module TTFunk
71
131
  end
72
132
  end
73
133
 
134
+ # Is this a composite glyph?
135
+ # @return [true]
74
136
  def compound?
75
137
  true
76
138
  end
77
139
 
140
+ # Recode glyph.
141
+ #
142
+ # @param mapping [Hash{Integer => Integer}] a hash mapping old glyph IDs
143
+ # to new glyph IDs.
144
+ # @return [String]
78
145
  def recode(mapping)
79
146
  result = raw.dup
80
147
  new_ids = glyph_ids.map { |id| mapping[id] }
@@ -3,11 +3,42 @@
3
3
  module TTFunk
4
4
  class Table
5
5
  class Glyf
6
+ # TrueType-compatible representation of a CFF glyph.
6
7
  class PathBased
7
- attr_reader :path, :horizontal_metrics
8
- attr_reader :x_min, :y_min, :x_max, :y_max
9
- attr_reader :left_side_bearing, :right_side_bearing
8
+ # Glyph outline.
9
+ # @return [TTFunk::Table::Cff::Path]
10
+ attr_reader :path
10
11
 
12
+ # Glyph horizontal metrics.
13
+ # @return [TTFunk::Table::Hmtx::HorizontalMetric]
14
+ attr_reader :horizontal_metrics
15
+
16
+ # Minimum X.
17
+ # @return [Integer, Float]
18
+ attr_reader :x_min
19
+
20
+ # Minimum Y.
21
+ # @return [Integer, Float]
22
+ attr_reader :y_min
23
+
24
+ # Maximum X.
25
+ # @return [Integer, Float]
26
+ attr_reader :x_max
27
+
28
+ # Maximum Y.
29
+ # @return [Integer, Float]
30
+ attr_reader :y_max
31
+
32
+ # Left side bearing.
33
+ # @return [Integer, Float]
34
+ attr_reader :left_side_bearing
35
+
36
+ # Rigth side bearing.
37
+ # @return [Integer, Float]
38
+ attr_reader :right_side_bearing
39
+
40
+ # @param path [TTFunk::Table::Cff::Path]
41
+ # @param horizontal_metrics [TTFunk::Table::Hmtx::HorizontalMetric]
11
42
  def initialize(path, horizontal_metrics)
12
43
  @path = path
13
44
  @horizontal_metrics = horizontal_metrics
@@ -34,10 +65,16 @@ module TTFunk
34
65
  (@x_max - @x_min)
35
66
  end
36
67
 
68
+ # Number of contour.
69
+ #
70
+ # @return [Integer]
37
71
  def number_of_contours
38
72
  path.number_of_contours
39
73
  end
40
74
 
75
+ # Is this glyph compound?
76
+ #
77
+ # @return [false]
41
78
  def compound?
42
79
  false
43
80
  end
@@ -5,36 +5,81 @@ require_relative '../../reader'
5
5
  module TTFunk
6
6
  class Table
7
7
  class Glyf
8
+ # Simple TrueType glyph
8
9
  class Simple
9
- attr_reader :id, :raw
10
+ # Glyph ID.
11
+ # @return [Integer]
12
+ attr_reader :id
13
+
14
+ # Binary serialization of this glyph.
15
+ # @return [String]
16
+ attr_reader :raw
17
+
18
+ # Number of contours in this glyph.
19
+ # @return [Integer]
10
20
  attr_reader :number_of_contours
11
- attr_reader :x_min, :y_min, :x_max, :y_max
21
+
22
+ # Minimum x for coordinate.
23
+ # @return [Integer]
24
+ attr_reader :x_min
25
+
26
+ # Minimum y for coordinate.
27
+ # @return [Integer]
28
+ attr_reader :y_min
29
+
30
+ # Maximum x for coordinate.
31
+ # @return [Integer]
32
+ attr_reader :x_max
33
+
34
+ # Maximum y for coordinate.
35
+ # @return [Integer]
36
+ attr_reader :y_max
37
+
38
+ # Point indices for the last point of each contour.
39
+ # @return [Array<Integer>]
12
40
  attr_reader :end_points_of_contours
13
- attr_reader :instruction_length, :instructions
14
41
 
42
+ # Total number of bytes for instructions.
43
+ # @return [Integer]
44
+ attr_reader :instruction_length
45
+
46
+ # Instruction byte code.
47
+ # @return [Array<Integer>]
48
+ attr_reader :instructions
49
+
50
+ # @param id [Integer] glyph ID.
51
+ # @param raw [String]
15
52
  def initialize(id, raw)
16
53
  @id = id
17
54
  @raw = raw
18
55
  io = StringIO.new(raw)
19
56
 
20
57
  @number_of_contours, @x_min, @y_min, @x_max, @y_max =
21
- io.read(10).unpack('n*').map do |i|
58
+ io.read(10).unpack('n*').map { |i|
22
59
  BinUtils.twos_comp_to_int(i, bit_width: 16)
23
- end
60
+ }
24
61
 
25
62
  @end_points_of_contours = io.read(number_of_contours * 2).unpack('n*')
26
63
  @instruction_length = io.read(2).unpack1('n')
27
64
  @instructions = io.read(instruction_length).unpack('C*')
28
65
  end
29
66
 
67
+ # Is this glyph compound?
68
+ # @return [false]
30
69
  def compound?
31
70
  false
32
71
  end
33
72
 
73
+ # Recode glyph.
74
+ #
75
+ # @param _mapping Unused, here for API compatibility.
76
+ # @return [String]
34
77
  def recode(_mapping)
35
78
  raw
36
79
  end
37
80
 
81
+ # End point index of last contour.
82
+ # @return [Integer]
38
83
  def end_point_of_last_contour
39
84
  end_points_of_contours.last + 1
40
85
  end
@@ -4,15 +4,18 @@ require_relative '../table'
4
4
 
5
5
  module TTFunk
6
6
  class Table
7
+ # Glyph Data (`glyf`) table.
7
8
  class Glyf < Table
8
- # Accepts a hash mapping (old) glyph-ids to glyph objects, and a hash
9
- # mapping old glyph-ids to new glyph-ids.
9
+ # Encode table.
10
10
  #
11
- # Returns a hash containing:
12
- #
13
- # * :table - a string representing the encoded 'glyf' table containing
14
- # the given glyphs.
15
- # * :offsets - an array of offsets for each glyph
11
+ # @param glyphs [Hash] a hash mapping (old) glyph-ids to glyph objects
12
+ # @param new_to_old [Hash{Integer => Integer}] a hash mapping new glyph
13
+ # IDs to glyph IDs in the original font.
14
+ # @param old_to_new [Hash{Integer => Integer}] a hash mapping old glyph
15
+ # IDs to new glyph IDs.
16
+ # @return [Hash]
17
+ # * `:table` (<tt>String</tt>) - encoded table.
18
+ # * `:offsets` (<tt>Array\<Integer></tt>) - glyph offsets in the table.
16
19
  def self.encode(glyphs, new_to_old, old_to_new)
17
20
  result = { table: +'', offsets: [] }
18
21
 
@@ -28,6 +31,11 @@ module TTFunk
28
31
  result
29
32
  end
30
33
 
34
+ # Get glyph by ID.
35
+ #
36
+ # @param glyph_id [Integer]
37
+ # @return [TTFunk::Table::Glyf::Simple, TTFunk::Table::Glyf::Compound,
38
+ # nil]
31
39
  def for(glyph_id)
32
40
  return @cache[glyph_id] if @cache.key?(glyph_id)
33
41