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