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.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +2 -1
- data.tar.gz.sig +0 -0
- data/CHANGELOG.md +15 -1
- data/lib/ttfunk.rb +3 -2
- data/lib/ttfunk/bit_field.rb +1 -1
- data/lib/ttfunk/collection.rb +8 -2
- data/lib/ttfunk/encoded_string.rb +3 -3
- data/lib/ttfunk/max.rb +1 -0
- data/lib/ttfunk/min.rb +1 -0
- data/lib/ttfunk/one_based_array.rb +1 -1
- data/lib/ttfunk/otf_encoder.rb +1 -1
- data/lib/ttfunk/reader.rb +3 -3
- data/lib/ttfunk/sci_form.rb +1 -1
- data/lib/ttfunk/subset.rb +3 -3
- data/lib/ttfunk/subset/base.rb +24 -21
- data/lib/ttfunk/subset/code_page.rb +16 -19
- data/lib/ttfunk/subset/unicode.rb +8 -6
- data/lib/ttfunk/subset/unicode_8bit.rb +14 -12
- data/lib/ttfunk/sum.rb +1 -0
- data/lib/ttfunk/table/cff.rb +17 -17
- data/lib/ttfunk/table/cff/charset.rb +31 -30
- data/lib/ttfunk/table/cff/charsets.rb +3 -3
- data/lib/ttfunk/table/cff/charstring.rb +54 -55
- data/lib/ttfunk/table/cff/dict.rb +6 -4
- data/lib/ttfunk/table/cff/encoding.rb +20 -21
- data/lib/ttfunk/table/cff/encodings.rb +1 -1
- data/lib/ttfunk/table/cff/fd_selector.rb +14 -11
- data/lib/ttfunk/table/cff/font_index.rb +7 -6
- data/lib/ttfunk/table/cff/index.rb +6 -5
- data/lib/ttfunk/table/cff/one_based_index.rb +7 -3
- data/lib/ttfunk/table/cff/path.rb +5 -3
- data/lib/ttfunk/table/cff/top_dict.rb +7 -6
- data/lib/ttfunk/table/cff/top_index.rb +5 -4
- data/lib/ttfunk/table/cmap.rb +8 -6
- data/lib/ttfunk/table/cmap/format00.rb +7 -6
- data/lib/ttfunk/table/cmap/format04.rb +16 -15
- data/lib/ttfunk/table/cmap/format06.rb +6 -5
- data/lib/ttfunk/table/cmap/format10.rb +6 -5
- data/lib/ttfunk/table/cmap/format12.rb +13 -12
- data/lib/ttfunk/table/cmap/subtable.rb +4 -4
- data/lib/ttfunk/table/dsig.rb +11 -9
- data/lib/ttfunk/table/glyf.rb +3 -3
- data/lib/ttfunk/table/glyf/compound.rb +8 -8
- data/lib/ttfunk/table/hmtx.rb +6 -5
- data/lib/ttfunk/table/kern.rb +4 -4
- data/lib/ttfunk/table/kern/format0.rb +1 -1
- data/lib/ttfunk/table/loca.rb +7 -6
- data/lib/ttfunk/table/name.rb +6 -5
- data/lib/ttfunk/table/os2.rb +261 -151
- data/lib/ttfunk/table/post.rb +1 -1
- data/lib/ttfunk/table/sbix.rb +15 -13
- data/lib/ttfunk/table/vorg.rb +1 -1
- data/lib/ttfunk/ttf_encoder.rb +4 -4
- metadata +29 -99
- 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),
|
48
|
-
|
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 ||=
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
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] ||=
|
9
|
-
|
10
|
-
|
11
|
-
|
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
|
data/lib/ttfunk/table/cmap.rb
CHANGED
@@ -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 ||=
|
21
|
-
|
22
|
-
|
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 =
|
30
|
-
|
31
|
-
|
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 =
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
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 =
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
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
|
-
|
37
|
-
|
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]
|
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 =
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
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 =
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
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 =
|
19
|
-
|
20
|
-
|
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
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
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
|
61
|
-
when 4
|
62
|
-
when 6
|
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
|
74
|
+
platform_id.zero? && format != 0
|
75
75
|
end
|
76
76
|
|
77
77
|
def supported?
|
data/lib/ttfunk/table/dsig.rb
CHANGED
@@ -19,7 +19,7 @@ module TTFunk
|
|
19
19
|
TAG = 'DSIG'
|
20
20
|
|
21
21
|
def self.encode(dsig)
|
22
|
-
return
|
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 =
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
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
|
-
|
46
|
-
|
47
|
+
SignatureRecord.new(format, length, sig_offset, signature)
|
48
|
+
end
|
47
49
|
end
|
48
50
|
end
|
49
51
|
end
|
data/lib/ttfunk/table/glyf.rb
CHANGED
@@ -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
|
35
|
+
size = file.glyph_locations.size_of(glyph_id)
|
36
36
|
|
37
|
-
if size
|
37
|
+
if size.zero? # blank glyph, e.g. space character
|
38
38
|
@cache[glyph_id] = nil
|
39
|
-
return
|
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
|
12
|
-
WE_HAVE_A_SCALE
|
13
|
-
MORE_COMPONENTS
|
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
|
16
|
-
WE_HAVE_INSTRUCTIONS
|
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
|
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
|
data/lib/ttfunk/table/hmtx.rb
CHANGED
@@ -10,10 +10,11 @@ module TTFunk
|
|
10
10
|
attr_reader :widths
|
11
11
|
|
12
12
|
def self.encode(hmtx, mapping)
|
13
|
-
metrics =
|
14
|
-
|
15
|
-
|
16
|
-
|
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
|
47
|
+
lsb = read_signed(1).first
|
47
48
|
@metrics.push HorizontalMetric.new(advance, lsb)
|
48
49
|
end
|
49
50
|
|
data/lib/ttfunk/table/kern.rb
CHANGED
@@ -9,10 +9,10 @@ module TTFunk
|
|
9
9
|
attr_reader :tables
|
10
10
|
|
11
11
|
def self.encode(kerning, mapping)
|
12
|
-
return
|
12
|
+
return unless kerning.exists? && kerning.tables.any?
|
13
13
|
|
14
14
|
tables = kerning.tables.map { |table| table.recode(mapping) }.compact
|
15
|
-
return
|
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
|
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
|
82
|
+
if format.zero?
|
83
83
|
@tables << Kern::Format0.new(attributes)
|
84
84
|
end
|
85
85
|
# Unsupported kerning tables are silently ignored
|
data/lib/ttfunk/table/loca.rb
CHANGED
@@ -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 =
|
19
|
-
|
20
|
-
|
21
|
-
|
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
|
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
|
45
|
+
if file.header.index_to_loc_format.zero?
|
45
46
|
@offsets.map! { |v| v * 2 }
|
46
47
|
end
|
47
48
|
end
|
data/lib/ttfunk/table/name.rb
CHANGED
@@ -76,7 +76,7 @@ module TTFunk
|
|
76
76
|
|
77
77
|
strings = names.strings.dup
|
78
78
|
strings[6] = [postscript_name]
|
79
|
-
str_count = strings.
|
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 =
|
91
|
-
|
92
|
-
|
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
|
-
|
155
|
+
.first.strip_extended
|
155
156
|
end
|
156
157
|
|
157
158
|
@trademark = @strings[TRADEMARK_NAME_ID]
|