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
@@ -4,27 +4,91 @@ require_relative '../table'
4
4
 
5
5
  module TTFunk
6
6
  class Table
7
+ # Font Header (`head`) Table.
7
8
  class Head < TTFunk::Table
9
+ # Table version.
10
+ # @return [Integer]
8
11
  attr_reader :version
12
+
13
+ # Font revision.
14
+ # @return [Integer]
9
15
  attr_reader :font_revision
16
+
17
+ # Checksum adjustment.
18
+ # @return [Integer]
10
19
  attr_reader :checksum_adjustment
20
+
21
+ # Magic number.
22
+ # @return [Integer] must be `0x5F0F3CF5`
11
23
  attr_reader :magic_number
24
+
25
+ # Flags.
26
+ # @return [Integer]
12
27
  attr_reader :flags
28
+
29
+ # Units per Em.
30
+ # @return [Integer]
13
31
  attr_reader :units_per_em
32
+
33
+ # Font creation time.
34
+ # @return [Integer] Long Date Time timestamp.
14
35
  attr_reader :created
36
+
37
+ # Font modification time.
38
+ # @return [Integer] Long Date Time timestamp.
15
39
  attr_reader :modified
40
+
41
+ # Minimum x coordinate across all glyph bounding boxes.
42
+ # @return [Integer]
16
43
  attr_reader :x_min
44
+
45
+ # Minimum y coordinate across all glyph bounding boxes.
46
+ # @return [Integer]
17
47
  attr_reader :y_min
48
+
49
+ # Maximum x coordinate across all glyph bounding boxes.
50
+ # @return [Integer]
18
51
  attr_reader :x_max
52
+
53
+ # Maximum y coordinate across all glyph bounding boxes.
54
+ # @return [Integer]
19
55
  attr_reader :y_max
56
+
57
+ # Mac font style.
58
+ # @return [Integer]
20
59
  attr_reader :mac_style
60
+
61
+ # Smallest readable size in pixels.
62
+ # @return [Integer]
21
63
  attr_reader :lowest_rec_ppem
64
+
65
+ # Font direction hint. Deprecated, set to 2.
66
+ # @return [Integer]
22
67
  attr_reader :font_direction_hint
68
+
69
+ # Index to Location format.
70
+ # @return [Integer]
23
71
  attr_reader :index_to_loc_format
72
+
73
+ # Glyph data format.
74
+ # @return [Integer]
24
75
  attr_reader :glyph_data_format
25
76
 
26
77
  class << self
27
- # mapping is new -> old glyph ids
78
+ # Long date time (used in TTF headers).
79
+ # January 1, 1904 00:00:00 UTC basis used by Long date time.
80
+ # @see https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6.html
81
+ # TrueType Font Tables
82
+ LONG_DATE_TIME_BASIS = Time.new(1904, 1, 1, 0, 0, 0, 0).to_i
83
+ private_constant :LONG_DATE_TIME_BASIS
84
+
85
+ # Encode table.
86
+ #
87
+ # @param head [TTFunk::Table::Head]
88
+ # @param loca [Hash] result of encoding Index to Location (`loca`) table
89
+ # @param mapping [Hash{Integer => Integer}] keys are new glyph IDs, values
90
+ # are old glyph IDs
91
+ # @return [EncodedString]
28
92
  def encode(head, loca, mapping)
29
93
  EncodedString.new do |table|
30
94
  table <<
@@ -36,11 +100,25 @@ module TTFunk
36
100
  head.created, head.modified,
37
101
  *min_max_values_for(head, mapping),
38
102
  head.mac_style, head.lowest_rec_ppem, head.font_direction_hint,
39
- loca[:type] || 0, head.glyph_data_format
40
- ].pack('Nn2q2n*')
103
+ loca[:type] || 0, head.glyph_data_format,
104
+ ].pack('Nn2q>2n*')
41
105
  end
42
106
  end
43
107
 
108
+ # Convert Long Date Time timestamp to Time.
109
+ # @param ldt [Float, Integer]
110
+ # @return [Time]
111
+ def from_long_date_time(ldt)
112
+ Time.at(ldt + LONG_DATE_TIME_BASIS, in: 'UTC')
113
+ end
114
+
115
+ # Convert Time to Long Date Time timestamp
116
+ # @param time [Time]
117
+ # @return [Integer]
118
+ def to_long_date_time(time)
119
+ Integer(time) - LONG_DATE_TIME_BASIS
120
+ end
121
+
44
122
  private
45
123
 
46
124
  def min_max_values_for(head, mapping)
@@ -49,7 +127,7 @@ module TTFunk
49
127
  y_min = Min.new
50
128
  y_max = Max.new
51
129
 
52
- mapping.each do |_, old_glyph_id|
130
+ mapping.each_value do |old_glyph_id|
53
131
  glyph = head.file.find_glyph(old_glyph_id)
54
132
  next unless glyph
55
133
 
@@ -61,7 +139,7 @@ module TTFunk
61
139
 
62
140
  [
63
141
  x_min.value_or(0), y_min.value_or(0),
64
- x_max.value_or(0), y_max.value_or(0)
142
+ x_max.value_or(0), y_max.value_or(0),
65
143
  ]
66
144
  end
67
145
  end
@@ -70,7 +148,7 @@ module TTFunk
70
148
 
71
149
  def parse!
72
150
  @version, @font_revision, @check_sum_adjustment, @magic_number,
73
- @flags, @units_per_em, @created, @modified = read(36, 'N4n2q2')
151
+ @flags, @units_per_em, @created, @modified = read(36, 'N4n2q>2')
74
152
 
75
153
  @x_min, @y_min, @x_max, @y_max = read_signed(4)
76
154
 
@@ -4,30 +4,92 @@ require_relative '../table'
4
4
 
5
5
  module TTFunk
6
6
  class Table
7
+ # Horizontal Header (`hhea`) table.
7
8
  class Hhea < Table
9
+ # Table version
10
+ # @return [Integer]
8
11
  attr_reader :version
12
+
13
+ # Typographic ascent.
14
+ # @return [Integer]
9
15
  attr_reader :ascent
16
+
17
+ # Typographic descent.
18
+ # @return [Integer]
10
19
  attr_reader :descent
20
+
21
+ # Typographic line gap.
22
+ # @return [Integer]
11
23
  attr_reader :line_gap
24
+
25
+ # Maximum advance width value in `hmtx` table.
26
+ # @return [Integer]
12
27
  attr_reader :advance_width_max
28
+
29
+ # Minimum left sidebearing value in `hmtx` table for glyphs with contours
30
+ # (empty glyphs should be ignored).
31
+ # @return [Integer]
13
32
  attr_reader :min_left_side_bearing
33
+
34
+ # Minimum right sidebearing value.
35
+ # @return [Integer]
14
36
  attr_reader :min_right_side_bearing
37
+
38
+ # Maximum extent.
39
+ # @return [Integer]
15
40
  attr_reader :x_max_extent
16
- attr_reader :carot_slope_rise
17
- attr_reader :carot_slope_run
41
+
42
+ # Caret slope rise.
43
+ # @return [Integer]
44
+ attr_reader :caret_slope_rise
45
+
46
+ # @deprecated Use {caret_slope_rise} instead.
47
+ # @!parse attr_reader :carot_slope_rise
48
+ # @return [Integer]
49
+ def carot_slope_rise
50
+ @caret_slope_rise
51
+ end
52
+
53
+ # Caret slope run.
54
+ # @return [Integer]
55
+ attr_reader :caret_slope_run
56
+
57
+ # @deprecated Use {caret_slope_run} instead.
58
+ # @!parse attr_reader :carot_slope_run
59
+ # @return [Integer]
60
+ def carot_slope_run
61
+ @caret_slope_run
62
+ end
63
+
64
+ # Caret offset.
65
+ # @return [Integer]
18
66
  attr_reader :caret_offset
67
+
68
+ # Metric data format. `0` for current format.
69
+ # @return [Integer]
19
70
  attr_reader :metric_data_format
71
+
72
+ # Number of hMetric entries in `hmtx` table.
73
+ # @return [Integer]
20
74
  attr_reader :number_of_metrics
21
75
 
22
76
  class << self
77
+ # Encode table.
78
+ #
79
+ # @param hhea [TTFunk::Table::Hhea] table to encode.
80
+ # @param hmtx [TTFunk::Table::Hmtx]
81
+ # @param original [TTFunk::File] original font file.
82
+ # @param mapping [Hash{Integer => Integer}] keys are new glyph IDs, values
83
+ # are old glyph IDs
84
+ # @return [String]
23
85
  def encode(hhea, hmtx, original, mapping)
24
86
  ''.b.tap do |table|
25
87
  table << [hhea.version].pack('N')
26
88
  table << [
27
89
  hhea.ascent, hhea.descent, hhea.line_gap,
28
90
  *min_max_values_for(original, mapping),
29
- hhea.carot_slope_rise, hhea.carot_slope_run, hhea.caret_offset,
30
- 0, 0, 0, 0, hhea.metric_data_format, hmtx[:number_of_metrics]
91
+ hhea.caret_slope_rise, hhea.caret_slope_run, hhea.caret_offset,
92
+ 0, 0, 0, 0, hhea.metric_data_format, hmtx[:number_of_metrics],
31
93
  ].pack('n*')
32
94
  end
33
95
  end
@@ -40,7 +102,7 @@ module TTFunk
40
102
  max_aw = Max.new
41
103
  max_extent = Max.new
42
104
 
43
- mapping.each do |_, old_glyph_id|
105
+ mapping.each_value do |old_glyph_id|
44
106
  horiz_metrics = original.horizontal_metrics.for(old_glyph_id)
45
107
  next unless horiz_metrics
46
108
 
@@ -52,15 +114,14 @@ module TTFunk
52
114
 
53
115
  x_delta = glyph.x_max - glyph.x_min
54
116
 
55
- min_rsb << horiz_metrics.advance_width -
56
- horiz_metrics.left_side_bearing - x_delta
117
+ min_rsb << (horiz_metrics.advance_width - horiz_metrics.left_side_bearing - x_delta)
57
118
 
58
- max_extent << horiz_metrics.left_side_bearing + x_delta
119
+ max_extent << (horiz_metrics.left_side_bearing + x_delta)
59
120
  end
60
121
 
61
122
  [
62
123
  max_aw.value_or(0), min_lsb.value_or(0),
63
- min_rsb.value_or(0), max_extent.value_or(0)
124
+ min_rsb.value_or(0), max_extent.value_or(0),
64
125
  ]
65
126
  end
66
127
  end
@@ -73,7 +134,7 @@ module TTFunk
73
134
  @advance_width_max = read(2, 'n').first
74
135
 
75
136
  @min_left_side_bearing, @min_right_side_bearing, @x_max_extent,
76
- @carot_slope_rise, @carot_slope_run, @caret_offset,
137
+ @caret_slope_rise, @caret_slope_run, @caret_offset,
77
138
  _reserved, _reserved, _reserved, _reserved,
78
139
  @metric_data_format = read_signed(11)
79
140
 
@@ -4,32 +4,59 @@ require_relative '../table'
4
4
 
5
5
  module TTFunk
6
6
  class Table
7
+ # Horizontal Metrics (`hmtx`) table.
7
8
  class Hmtx < Table
9
+ # Glyph horizontal metrics.
10
+ # @return [Array<HorizontalMetric>]
8
11
  attr_reader :metrics
12
+
13
+ # Left side bearings.
14
+ # @return [Array<Ingteger>]
9
15
  attr_reader :left_side_bearings
16
+
17
+ # Glyph widths.
18
+ # @return [Array<Integer>]
10
19
  attr_reader :widths
11
20
 
21
+ # Encode table.
22
+ #
23
+ # @param hmtx [TTFunk::Table::Hmtx]
24
+ # @param mapping [Hash{Integer => Integer}] keys are new glyph IDs, values
25
+ # are old glyph IDs
26
+ # @return [Hash{:number_of_metrics => Integer, :table => String}]
27
+ # * `:number_of_metrics` - number of mertrics is the table.
28
+ # * `:table` - encoded table.
12
29
  def self.encode(hmtx, mapping)
13
30
  metrics =
14
- mapping.keys.sort.map do |new_id|
31
+ mapping.keys.sort.map { |new_id|
15
32
  metric = hmtx.for(mapping[new_id])
16
33
  [metric.advance_width, metric.left_side_bearing]
17
- end
34
+ }
18
35
 
19
36
  {
20
37
  number_of_metrics: metrics.length,
21
- table: metrics.flatten.pack('n*')
38
+ table: metrics.flatten.pack('n*'),
22
39
  }
23
40
  end
24
41
 
42
+ # Horyzontal glyph metric.
43
+ #
44
+ # @!attribute [rw] advance_width
45
+ # @return [Integer] Advance width.
46
+ # @!attribute [rw] left_side_bearing
47
+ # @return [Integer] Left side bearing.
25
48
  HorizontalMetric = Struct.new(:advance_width, :left_side_bearing)
26
49
 
50
+ # Get horizontal metric for glyph.
51
+ #
52
+ # @param glyph_id [Integer]
53
+ # @return [HorizontalMetric]
27
54
  def for(glyph_id)
28
55
  @metrics[glyph_id] ||
29
56
  metrics_cache[glyph_id] ||=
30
57
  HorizontalMetric.new(
31
58
  @metrics.last.advance_width,
32
- @left_side_bearings[glyph_id - @metrics.length]
59
+ @left_side_bearings[glyph_id - @metrics.length],
33
60
  )
34
61
  end
35
62
 
@@ -45,7 +72,7 @@ module TTFunk
45
72
  file.horizontal_header.number_of_metrics.times do
46
73
  advance = read(2, 'n').first
47
74
  lsb = read_signed(1).first
48
- @metrics.push HorizontalMetric.new(advance, lsb)
75
+ @metrics.push(HorizontalMetric.new(advance, lsb))
49
76
  end
50
77
 
51
78
  lsb_count = file.maximum_profile.num_glyphs -
@@ -5,12 +5,19 @@ require_relative '../../reader'
5
5
  module TTFunk
6
6
  class Table
7
7
  class Kern
8
+ # Format 0 kerning subtable.
8
9
  class Format0
9
10
  include Reader
10
11
 
12
+ # Subtable attributes.
13
+ # @return [Hash{Symbol => any}]
11
14
  attr_reader :attributes
15
+
16
+ # Kerning pairs.
17
+ # @return [Hash{Array(Integer, Integer) => Integer}]
12
18
  attr_reader :pairs
13
19
 
20
+ # @param attributes [Hash{Symbol => any}]
14
21
  def initialize(attributes = {})
15
22
  @attributes = attributes
16
23
 
@@ -19,27 +26,38 @@ module TTFunk
19
26
  @pairs = {}
20
27
  num_pairs.times do |i|
21
28
  # sanity check, in case there's a bad length somewhere
22
- break if i * 3 + 2 > pairs.length
29
+ break if (i * 3) + 2 > pairs.length
23
30
 
24
31
  left = pairs[i * 3]
25
- right = pairs[i * 3 + 1]
26
- value = to_signed(pairs[i * 3 + 2])
32
+ right = pairs[(i * 3) + 1]
33
+ value = to_signed(pairs[(i * 3) + 2])
27
34
  @pairs[[left, right]] = value
28
35
  end
29
36
  end
30
37
 
38
+ # Is this vertical kerning?
39
+ # @return [Boolean]
31
40
  def vertical?
32
41
  @attributes[:vertical]
33
42
  end
34
43
 
44
+ # Is this horizontal kerning?
45
+ # @return [Boolean]
35
46
  def horizontal?
36
47
  !vertical?
37
48
  end
38
49
 
50
+ # Is this cross-stream kerning?
51
+ # @return [Boolean]
39
52
  def cross_stream?
40
53
  @attributes[:cross]
41
54
  end
42
55
 
56
+ # Recode this subtable using the specified mapping.
57
+ #
58
+ # @param mapping [Hash{Integer => Integer}] keys are new glyph IDs,
59
+ # values are old glyph IDs
60
+ # @return [String]
43
61
  def recode(mapping)
44
62
  subset = []
45
63
  pairs.each do |(left, right), value|
@@ -51,19 +69,19 @@ module TTFunk
51
69
  return if subset.empty?
52
70
 
53
71
  num_pairs = subset.length
54
- search_range = 2 * 2**(Math.log(num_pairs) / Math.log(2)).to_i
55
- entry_selector = (Math.log(search_range / 2) / Math.log(2)).to_i
72
+ search_range = 2 * (2**Integer(Math.log(num_pairs) / Math.log(2)))
73
+ entry_selector = Integer(Math.log(search_range / 2) / Math.log(2))
56
74
  range_shift = (2 * num_pairs) - search_range
57
75
 
58
76
  [
59
77
  attributes[:version],
60
- num_pairs * 6 + 14,
78
+ (num_pairs * 6) + 14,
61
79
  attributes[:coverage],
62
80
  num_pairs,
63
81
  search_range,
64
82
  entry_selector,
65
83
  range_shift,
66
- subset
84
+ subset,
67
85
  ].flatten.pack('n*')
68
86
  end
69
87
  end
@@ -4,14 +4,26 @@ require_relative '../table'
4
4
 
5
5
  module TTFunk
6
6
  class Table
7
+ # Kerning (`kern`) table
7
8
  class Kern < Table
9
+ # Table version
10
+ # @return [Integer]
8
11
  attr_reader :version
12
+
13
+ # Subtables.
14
+ # @return [Array<TTFunk::Table::Kern::Format0>]
9
15
  attr_reader :tables
10
16
 
17
+ # Encode table.
18
+ #
19
+ # @param kerning [TTFunk::Table::Kern]
20
+ # @param mapping [Hash{Integer => Integer}] keys are new glyph IDs, values
21
+ # are old glyph IDs
22
+ # @return [String, nil]
11
23
  def self.encode(kerning, mapping)
12
24
  return unless kerning.exists? && kerning.tables.any?
13
25
 
14
- tables = kerning.tables.map { |table| table.recode(mapping) }.compact
26
+ tables = kerning.tables.filter_map { |table| table.recode(mapping) }
15
27
  return if tables.empty?
16
28
 
17
29
  [0, tables.length, tables.join].pack('nnA*')
@@ -52,11 +64,11 @@ module TTFunk
52
64
  version: version,
53
65
  length: length,
54
66
  coverage: coverage,
55
- data: raw[10..-1],
67
+ data: raw[10..],
56
68
  vertical: (coverage & 0x1).zero?,
57
69
  minimum: (coverage & 0x2 != 0),
58
70
  cross: (coverage & 0x4 != 0),
59
- override: (coverage & 0x8 != 0)
71
+ override: (coverage & 0x8 != 0),
60
72
  )
61
73
  end
62
74
 
@@ -73,7 +85,7 @@ module TTFunk
73
85
  data: io.read(length - 8),
74
86
  vertical: (coverage & 0x8000 != 0),
75
87
  cross: (coverage & 0x4000 != 0),
76
- variation: (coverage & 0x2000 != 0)
88
+ variation: (coverage & 0x2000 != 0),
77
89
  )
78
90
  end
79
91
  end
@@ -4,22 +4,27 @@ require_relative '../table'
4
4
 
5
5
  module TTFunk
6
6
  class Table
7
+ # Index to Location table.
7
8
  class Loca < Table
9
+ # Glyph ofsets
10
+ # @return [Array<Integer>]
8
11
  attr_reader :offsets
9
12
 
10
- # Accepts an array of offsets, with each index corresponding to the
11
- # glyph id with that index.
13
+ # Encode table.
12
14
  #
13
- # Returns a hash containing:
14
- #
15
- # * :table - the string representing the table's contents
16
- # * :type - the type of offset (to be encoded in the 'head' table)
15
+ # @param offsets [Array<Integer>] an array of offsets, with each index
16
+ # corresponding to the glyph id with that index.
17
+ # @return [Hash] result hash:
18
+ # * `:type` - the type of offset (to be encoded in the 'head' table):
19
+ # * `0` - short offsets
20
+ # * `1` - long offsets
21
+ # * `:table` - encoded bytes
17
22
  def self.encode(offsets)
18
23
  long_offsets =
19
- offsets.any? do |offset|
24
+ offsets.any? { |offset|
20
25
  short_offset = offset / 2
21
26
  short_offset * 2 != offset || short_offset > 0xffff
22
- end
27
+ }
23
28
 
24
29
  if long_offsets
25
30
  { type: 1, table: offsets.pack('N*') }
@@ -28,10 +33,18 @@ module TTFunk
28
33
  end
29
34
  end
30
35
 
36
+ # Glyph offset by ID.
37
+ #
38
+ # @param glyph_id [Integer]
39
+ # @return [Integer] - offset of the glyph in the `glyf` table
31
40
  def index_of(glyph_id)
32
41
  @offsets[glyph_id]
33
42
  end
34
43
 
44
+ # Size of encoded glyph.
45
+ #
46
+ # @param glyph_id [Integer]
47
+ # @return [Integer]
35
48
  def size_of(glyph_id)
36
49
  @offsets[glyph_id + 1] - @offsets[glyph_id]
37
50
  end