ttfunk 1.7.0 → 1.8.0

Sign up to get free protection for your applications and to get access to all the features.
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