ttfunk 1.6.2.1 → 1.7.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 (56) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +2 -1
  3. data.tar.gz.sig +0 -0
  4. data/CHANGELOG.md +15 -1
  5. data/lib/ttfunk.rb +3 -2
  6. data/lib/ttfunk/bit_field.rb +1 -1
  7. data/lib/ttfunk/collection.rb +8 -2
  8. data/lib/ttfunk/encoded_string.rb +3 -3
  9. data/lib/ttfunk/max.rb +1 -0
  10. data/lib/ttfunk/min.rb +1 -0
  11. data/lib/ttfunk/one_based_array.rb +1 -1
  12. data/lib/ttfunk/otf_encoder.rb +1 -1
  13. data/lib/ttfunk/reader.rb +3 -3
  14. data/lib/ttfunk/sci_form.rb +1 -1
  15. data/lib/ttfunk/subset.rb +3 -3
  16. data/lib/ttfunk/subset/base.rb +24 -21
  17. data/lib/ttfunk/subset/code_page.rb +16 -19
  18. data/lib/ttfunk/subset/unicode.rb +8 -6
  19. data/lib/ttfunk/subset/unicode_8bit.rb +14 -12
  20. data/lib/ttfunk/sum.rb +1 -0
  21. data/lib/ttfunk/table/cff.rb +17 -17
  22. data/lib/ttfunk/table/cff/charset.rb +31 -30
  23. data/lib/ttfunk/table/cff/charsets.rb +3 -3
  24. data/lib/ttfunk/table/cff/charstring.rb +54 -55
  25. data/lib/ttfunk/table/cff/dict.rb +6 -4
  26. data/lib/ttfunk/table/cff/encoding.rb +20 -21
  27. data/lib/ttfunk/table/cff/encodings.rb +1 -1
  28. data/lib/ttfunk/table/cff/fd_selector.rb +14 -11
  29. data/lib/ttfunk/table/cff/font_index.rb +7 -6
  30. data/lib/ttfunk/table/cff/index.rb +6 -5
  31. data/lib/ttfunk/table/cff/one_based_index.rb +7 -3
  32. data/lib/ttfunk/table/cff/path.rb +5 -3
  33. data/lib/ttfunk/table/cff/top_dict.rb +7 -6
  34. data/lib/ttfunk/table/cff/top_index.rb +5 -4
  35. data/lib/ttfunk/table/cmap.rb +8 -6
  36. data/lib/ttfunk/table/cmap/format00.rb +7 -6
  37. data/lib/ttfunk/table/cmap/format04.rb +16 -15
  38. data/lib/ttfunk/table/cmap/format06.rb +6 -5
  39. data/lib/ttfunk/table/cmap/format10.rb +6 -5
  40. data/lib/ttfunk/table/cmap/format12.rb +13 -12
  41. data/lib/ttfunk/table/cmap/subtable.rb +4 -4
  42. data/lib/ttfunk/table/dsig.rb +11 -9
  43. data/lib/ttfunk/table/glyf.rb +3 -3
  44. data/lib/ttfunk/table/glyf/compound.rb +8 -8
  45. data/lib/ttfunk/table/hmtx.rb +6 -5
  46. data/lib/ttfunk/table/kern.rb +4 -4
  47. data/lib/ttfunk/table/kern/format0.rb +1 -1
  48. data/lib/ttfunk/table/loca.rb +7 -6
  49. data/lib/ttfunk/table/name.rb +6 -5
  50. data/lib/ttfunk/table/os2.rb +261 -151
  51. data/lib/ttfunk/table/post.rb +1 -1
  52. data/lib/ttfunk/table/sbix.rb +15 -13
  53. data/lib/ttfunk/table/vorg.rb +1 -1
  54. data/lib/ttfunk/ttf_encoder.rb +4 -4
  55. metadata +29 -99
  56. metadata.gz.sig +0 -0
@@ -21,7 +21,7 @@ module TTFunk
21
21
  @commands << [:line, x, y]
22
22
  end
23
23
 
24
- def curve_to(x1, y1, x2, y2, x, y)
24
+ def curve_to(x1, y1, x2, y2, x, y) # rubocop: disable Metrics/ParameterLists,Style/CommentedKeyword
25
25
  @commands << [:curve, x1, y1, x2, y2, x, y]
26
26
  end
27
27
 
@@ -44,8 +44,10 @@ module TTFunk
44
44
  new_path.curve_to(
45
45
  x + (cmd[1] * scale),
46
46
  y + (-cmd[2] * scale),
47
- x + (cmd[3] * scale), y + (-cmd[4] * scale),
48
- x + (cmd[5] * scale), y + (-cmd[6] * scale)
47
+ x + (cmd[3] * scale),
48
+ y + (-cmd[4] * scale),
49
+ x + (cmd[5] * scale),
50
+ y + (-cmd[6] * scale)
49
51
  )
50
52
  when :close
51
53
  new_path.close_path
@@ -128,13 +128,14 @@ module TTFunk
128
128
  end
129
129
 
130
130
  def encoding
131
- @encoding ||= begin
132
- # PostScript type 1 fonts, i.e. CID fonts, i.e. some fonts that use
133
- # the CFF table, don't specify an encoding, so this can be nil
134
- if (encoding_offset_or_id = self[OPERATORS[:encoding]])
135
- Encoding.new(self, file, encoding_offset_or_id.first)
131
+ @encoding ||=
132
+ begin
133
+ # PostScript type 1 fonts, i.e. CID fonts, i.e. some fonts that use
134
+ # the CFF table, don't specify an encoding, so this can be nil
135
+ if (encoding_offset_or_id = self[OPERATORS[:encoding]])
136
+ Encoding.new(self, file, encoding_offset_or_id.first)
137
+ end
136
138
  end
137
- end
138
139
  end
139
140
 
140
141
  # https://www.microsoft.com/typography/otspec/cff.htm
@@ -5,10 +5,11 @@ module TTFunk
5
5
  class Cff < TTFunk::Table
6
6
  class TopIndex < TTFunk::Table::Cff::Index
7
7
  def [](index)
8
- entry_cache[index] ||= begin
9
- start, finish = absolute_offsets_for(index)
10
- TTFunk::Table::Cff::TopDict.new(file, start, (finish - start) + 1)
11
- end
8
+ entry_cache[index] ||=
9
+ begin
10
+ start, finish = absolute_offsets_for(index)
11
+ TTFunk::Table::Cff::TopDict.new(file, start, (finish - start) + 1)
12
+ end
12
13
  end
13
14
  end
14
15
  end
@@ -17,18 +17,20 @@ module TTFunk
17
17
  def unicode
18
18
  # Because most callers just call .first on the result, put tables with
19
19
  # highest-number format first. Unsupported formats will be ignored.
20
- @unicode ||= @tables
21
- .select { |table| table.unicode? && table.supported? }
22
- .sort { |a, b| b.format <=> a.format }
20
+ @unicode ||=
21
+ @tables
22
+ .select { |table| table.unicode? && table.supported? }
23
+ .sort { |a, b| b.format <=> a.format }
23
24
  end
24
25
 
25
26
  private
26
27
 
27
28
  def parse!
28
29
  @version, table_count = read(4, 'nn')
29
- @tables = Array.new(table_count) do
30
- Cmap::Subtable.new(file, offset)
31
- end
30
+ @tables =
31
+ Array.new(table_count) do
32
+ Cmap::Subtable.new(file, offset)
33
+ end
32
34
  end
33
35
  end
34
36
  end
@@ -18,12 +18,13 @@ module TTFunk
18
18
  glyph_indexes = Array.new(256, 0)
19
19
  glyph_map = { 0 => 0 }
20
20
 
21
- new_map = charmap.keys.sort.each_with_object({}) do |code, map|
22
- glyph_map[charmap[code]] ||= next_id += 1
23
- map[code] = { old: charmap[code], new: glyph_map[charmap[code]] }
24
- glyph_indexes[code] = glyph_map[charmap[code]]
25
- map
26
- end
21
+ new_map =
22
+ charmap.keys.sort.each_with_object({}) do |code, map|
23
+ glyph_map[charmap[code]] ||= next_id += 1
24
+ map[code] = { old: charmap[code], new: glyph_map[charmap[code]] }
25
+ glyph_indexes[code] = glyph_map[charmap[code]]
26
+ map
27
+ end
27
28
 
28
29
  # format, length, language, indices
29
30
  subtable = [0, 262, 0, *glyph_indexes].pack('nnnC*')
@@ -20,21 +20,22 @@ module TTFunk
20
20
  last = difference = nil
21
21
 
22
22
  glyph_map = { 0 => 0 }
23
- new_map = charmap.keys.sort.each_with_object({}) do |code, map|
24
- old = charmap[code]
25
- glyph_map[old] ||= next_id += 1
26
- map[code] = { old: old, new: glyph_map[old] }
27
-
28
- delta = glyph_map[old] - code
29
- if last.nil? || delta != difference
30
- end_codes << last if last
31
- start_codes << code
32
- difference = delta
33
- end
34
- last = code
23
+ new_map =
24
+ charmap.keys.sort.each_with_object({}) do |code, map|
25
+ old = charmap[code]
26
+ glyph_map[old] ||= next_id += 1
27
+ map[code] = { old: old, new: glyph_map[old] }
28
+
29
+ delta = glyph_map[old] - code
30
+ if last.nil? || delta != difference
31
+ end_codes << last if last
32
+ start_codes << code
33
+ difference = delta
34
+ end
35
+ last = code
35
36
 
36
- map
37
- end
37
+ map
38
+ end
38
39
 
39
40
  end_codes << last if last
40
41
  end_codes << 0xFFFF
@@ -119,7 +120,7 @@ module TTFunk
119
120
 
120
121
  end_code.each_with_index do |tail, i|
121
122
  start_code[i].upto(tail) do |code|
122
- if id_range_offset[i] == 0
123
+ if (id_range_offset[i]).zero?
123
124
  glyph_id = code + id_delta[i]
124
125
  else
125
126
  index = id_range_offset[i] / 2 +
@@ -17,11 +17,12 @@ module TTFunk
17
17
  entry_count = 1 + high_char - low_char
18
18
  glyph_indexes = Array.new(entry_count, 0)
19
19
 
20
- new_map = charmap.keys.sort.each_with_object({}) do |code, map|
21
- glyph_map[charmap[code]] ||= next_id += 1
22
- map[code] = { old: charmap[code], new: glyph_map[charmap[code]] }
23
- glyph_indexes[code - low_char] = glyph_map[charmap[code]]
24
- end
20
+ new_map =
21
+ charmap.keys.sort.each_with_object({}) do |code, map|
22
+ glyph_map[charmap[code]] ||= next_id += 1
23
+ map[code] = { old: charmap[code], new: glyph_map[charmap[code]] }
24
+ glyph_indexes[code - low_char] = glyph_map[charmap[code]]
25
+ end
25
26
 
26
27
  subtable = [
27
28
  6, 10 + entry_count * 2, 0, low_char, entry_count, *glyph_indexes
@@ -17,11 +17,12 @@ module TTFunk
17
17
  entry_count = 1 + high_char - low_char
18
18
  glyph_indexes = Array.new(entry_count, 0)
19
19
 
20
- new_map = charmap.keys.sort.each_with_object({}) do |code, map|
21
- glyph_map[charmap[code]] ||= next_id += 1
22
- map[code] = { old: charmap[code], new: glyph_map[charmap[code]] }
23
- glyph_indexes[code - low_char] = glyph_map[charmap[code]]
24
- end
20
+ new_map =
21
+ charmap.keys.sort.each_with_object({}) do |code, map|
22
+ glyph_map[charmap[code]] ||= next_id += 1
23
+ map[code] = { old: charmap[code], new: glyph_map[charmap[code]] }
24
+ glyph_indexes[code - low_char] = glyph_map[charmap[code]]
25
+ end
25
26
 
26
27
  subtable = [
27
28
  10, 0, 20 + entry_count * 4, 0, low_char, entry_count,
@@ -15,20 +15,21 @@ module TTFunk
15
15
  range_lengths = []
16
16
  last_glyph = last_code = -999
17
17
 
18
- new_map = charmap.keys.sort.each_with_object({}) do |code, map|
19
- glyph_map[charmap[code]] ||= next_id += 1
20
- map[code] = { old: charmap[code], new: glyph_map[charmap[code]] }
18
+ new_map =
19
+ charmap.keys.sort.each_with_object({}) do |code, map|
20
+ glyph_map[charmap[code]] ||= next_id += 1
21
+ map[code] = { old: charmap[code], new: glyph_map[charmap[code]] }
21
22
 
22
- if code > last_code + 1 || glyph_map[charmap[code]] > last_glyph + 1
23
- range_firstcodes << code
24
- range_firstglyphs << glyph_map[charmap[code]]
25
- range_lengths << 1
26
- else
27
- range_lengths.push(range_lengths.pop) + 1
23
+ if code > last_code + 1 || glyph_map[charmap[code]] > last_glyph + 1
24
+ range_firstcodes << code
25
+ range_firstglyphs << glyph_map[charmap[code]]
26
+ range_lengths << 1
27
+ else
28
+ range_lengths.push(range_lengths.pop) + 1
29
+ end
30
+ last_code = code
31
+ last_glyph = glyph_map[charmap[code]]
28
32
  end
29
- last_code = code
30
- last_glyph = glyph_map[charmap[code]]
31
- end
32
33
 
33
34
  subtable = [
34
35
  12, 0, 16 + 12 * range_lengths.size, 0, range_lengths.size
@@ -57,9 +57,9 @@ module TTFunk
57
57
  @format = read(2, 'n').first
58
58
 
59
59
  case @format
60
- when 0 then extend(TTFunk::Table::Cmap::Format00)
61
- when 4 then extend(TTFunk::Table::Cmap::Format04)
62
- when 6 then extend(TTFunk::Table::Cmap::Format06)
60
+ when 0 then extend(TTFunk::Table::Cmap::Format00)
61
+ when 4 then extend(TTFunk::Table::Cmap::Format04)
62
+ when 6 then extend(TTFunk::Table::Cmap::Format06)
63
63
  when 10 then extend(TTFunk::Table::Cmap::Format10)
64
64
  when 12 then extend(TTFunk::Table::Cmap::Format12)
65
65
  end
@@ -71,7 +71,7 @@ module TTFunk
71
71
  def unicode?
72
72
  platform_id == 3 && (encoding_id == 1 || encoding_id == 10) &&
73
73
  format != 0 ||
74
- platform_id == 0 && format != 0
74
+ platform_id.zero? && format != 0
75
75
  end
76
76
 
77
77
  def supported?
@@ -19,7 +19,7 @@ module TTFunk
19
19
  TAG = 'DSIG'
20
20
 
21
21
  def self.encode(dsig)
22
- return nil unless dsig
22
+ return unless dsig
23
23
 
24
24
  # Don't attempt to re-sign or anything - just use dummy values.
25
25
  # Since we're subsetting that should be permissible.
@@ -35,15 +35,17 @@ module TTFunk
35
35
  def parse!
36
36
  @version, num_signatures, @flags = read(8, 'Nnn')
37
37
 
38
- @signatures = Array.new(num_signatures) do
39
- format, length, sig_offset = read(12, 'N3')
40
- signature = parse_from(offset + sig_offset) do
41
- _, _, sig_length = read(8, 'nnN')
42
- read(sig_length, 'C*')
43
- end
38
+ @signatures =
39
+ Array.new(num_signatures) do
40
+ format, length, sig_offset = read(12, 'N3')
41
+ signature =
42
+ parse_from(offset + sig_offset) do
43
+ _, _, sig_length = read(8, 'nnN')
44
+ read(sig_length, 'C*')
45
+ end
44
46
 
45
- SignatureRecord.new(format, length, sig_offset, signature)
46
- end
47
+ SignatureRecord.new(format, length, sig_offset, signature)
48
+ end
47
49
  end
48
50
  end
49
51
  end
@@ -32,11 +32,11 @@ module TTFunk
32
32
  return @cache[glyph_id] if @cache.key?(glyph_id)
33
33
 
34
34
  index = file.glyph_locations.index_of(glyph_id)
35
- size = file.glyph_locations.size_of(glyph_id)
35
+ size = file.glyph_locations.size_of(glyph_id)
36
36
 
37
- if size == 0 # blank glyph, e.g. space character
37
+ if size.zero? # blank glyph, e.g. space character
38
38
  @cache[glyph_id] = nil
39
- return nil
39
+ return
40
40
  end
41
41
 
42
42
  parse_from(offset + index) do
@@ -8,12 +8,12 @@ module TTFunk
8
8
  class Compound
9
9
  include Reader
10
10
 
11
- ARG_1_AND_2_ARE_WORDS = 0x0001
12
- WE_HAVE_A_SCALE = 0x0008
13
- MORE_COMPONENTS = 0x0020
11
+ ARG_1_AND_2_ARE_WORDS = 0x0001
12
+ WE_HAVE_A_SCALE = 0x0008
13
+ MORE_COMPONENTS = 0x0020
14
14
  WE_HAVE_AN_X_AND_Y_SCALE = 0x0040
15
- WE_HAVE_A_TWO_BY_TWO = 0x0080
16
- WE_HAVE_INSTRUCTIONS = 0x0100
15
+ WE_HAVE_A_TWO_BY_TWO = 0x0080
16
+ WE_HAVE_INSTRUCTIONS = 0x0100
17
17
 
18
18
  attr_reader :id, :raw
19
19
  attr_reader :number_of_contours
@@ -55,10 +55,10 @@ module TTFunk
55
55
  offset += 4
56
56
 
57
57
  offset +=
58
- if flags & ARG_1_AND_2_ARE_WORDS != 0
59
- 4
60
- else
58
+ if (flags & ARG_1_AND_2_ARE_WORDS).zero?
61
59
  2
60
+ else
61
+ 4
62
62
  end
63
63
 
64
64
  if flags & WE_HAVE_A_TWO_BY_TWO != 0
@@ -10,10 +10,11 @@ module TTFunk
10
10
  attr_reader :widths
11
11
 
12
12
  def self.encode(hmtx, mapping)
13
- metrics = mapping.keys.sort.map do |new_id|
14
- metric = hmtx.for(mapping[new_id])
15
- [metric.advance_width, metric.left_side_bearing]
16
- end
13
+ metrics =
14
+ mapping.keys.sort.map do |new_id|
15
+ metric = hmtx.for(mapping[new_id])
16
+ [metric.advance_width, metric.left_side_bearing]
17
+ end
17
18
 
18
19
  {
19
20
  number_of_metrics: metrics.length,
@@ -43,7 +44,7 @@ module TTFunk
43
44
 
44
45
  file.horizontal_header.number_of_metrics.times do
45
46
  advance = read(2, 'n').first
46
- lsb = read_signed(1).first
47
+ lsb = read_signed(1).first
47
48
  @metrics.push HorizontalMetric.new(advance, lsb)
48
49
  end
49
50
 
@@ -9,10 +9,10 @@ module TTFunk
9
9
  attr_reader :tables
10
10
 
11
11
  def self.encode(kerning, mapping)
12
- return nil unless kerning.exists? && kerning.tables.any?
12
+ return unless kerning.exists? && kerning.tables.any?
13
13
 
14
14
  tables = kerning.tables.map { |table| table.recode(mapping) }.compact
15
- return nil if tables.empty?
15
+ return if tables.empty?
16
16
 
17
17
  [0, tables.length, tables.join].pack('nnA*')
18
18
  end
@@ -53,7 +53,7 @@ module TTFunk
53
53
  length: length,
54
54
  coverage: coverage,
55
55
  data: raw[10..-1],
56
- vertical: (coverage & 0x1 == 0),
56
+ vertical: (coverage & 0x1).zero?,
57
57
  minimum: (coverage & 0x2 != 0),
58
58
  cross: (coverage & 0x4 != 0),
59
59
  override: (coverage & 0x8 != 0)
@@ -79,7 +79,7 @@ module TTFunk
79
79
  end
80
80
 
81
81
  def add_table(format, attributes = {})
82
- if format == 0
82
+ if format.zero?
83
83
  @tables << Kern::Format0.new(attributes)
84
84
  end
85
85
  # Unsupported kerning tables are silently ignored
@@ -48,7 +48,7 @@ module TTFunk
48
48
  end
49
49
  end
50
50
 
51
- return nil if subset.empty?
51
+ return if subset.empty?
52
52
 
53
53
  num_pairs = subset.length
54
54
  search_range = 2 * 2**(Math.log(num_pairs) / Math.log(2)).to_i
@@ -15,10 +15,11 @@ module TTFunk
15
15
  # * :table - the string representing the table's contents
16
16
  # * :type - the type of offset (to be encoded in the 'head' table)
17
17
  def self.encode(offsets)
18
- long_offsets = offsets.any? do |offset|
19
- short_offset = offset / 2
20
- short_offset * 2 != offset || short_offset > 0xffff
21
- end
18
+ long_offsets =
19
+ offsets.any? do |offset|
20
+ short_offset = offset / 2
21
+ short_offset * 2 != offset || short_offset > 0xffff
22
+ end
22
23
 
23
24
  if long_offsets
24
25
  { type: 1, table: offsets.pack('N*') }
@@ -38,10 +39,10 @@ module TTFunk
38
39
  private
39
40
 
40
41
  def parse!
41
- type = file.header.index_to_loc_format == 0 ? 'n' : 'N'
42
+ type = file.header.index_to_loc_format.zero? ? 'n' : 'N'
42
43
  @offsets = read(length, "#{type}*")
43
44
 
44
- if file.header.index_to_loc_format == 0
45
+ if file.header.index_to_loc_format.zero?
45
46
  @offsets.map! { |v| v * 2 }
46
47
  end
47
48
  end
@@ -76,7 +76,7 @@ module TTFunk
76
76
 
77
77
  strings = names.strings.dup
78
78
  strings[6] = [postscript_name]
79
- str_count = strings.inject(0) { |sum, (_, list)| sum + list.length }
79
+ str_count = strings.reduce(0) { |sum, (_, list)| sum + list.length }
80
80
 
81
81
  table = [0, str_count, 6 + 12 * str_count].pack('n*')
82
82
  strtable = +''
@@ -87,9 +87,10 @@ module TTFunk
87
87
  items << [id, string]
88
88
  end
89
89
  end
90
- items = items.sort_by do |id, string|
91
- [string.platform_id, string.encoding_id, string.language_id, id]
92
- end
90
+ items =
91
+ items.sort_by do |id, string|
92
+ [string.platform_id, string.encoding_id, string.language_id, id]
93
+ end
93
94
  items.each do |id, string|
94
95
  table << [
95
96
  string.platform_id, string.encoding_id, string.language_id, id,
@@ -151,7 +152,7 @@ module TTFunk
151
152
 
152
153
  unless @strings[POSTSCRIPT_NAME_NAME_ID].empty?
153
154
  @postscript_name = @strings[POSTSCRIPT_NAME_NAME_ID]
154
- .first.strip_extended
155
+ .first.strip_extended
155
156
  end
156
157
 
157
158
  @trademark = @strings[TRADEMARK_NAME_ID]