ttfunk 1.7.0 → 1.8.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 +0 -0
- data/CHANGELOG.md +74 -0
- data/README.md +17 -15
- data/lib/ttfunk/aggregate.rb +5 -0
- data/lib/ttfunk/bin_utils.rb +27 -8
- data/lib/ttfunk/bit_field.rb +25 -2
- data/lib/ttfunk/collection.rb +27 -3
- data/lib/ttfunk/directory.rb +7 -1
- data/lib/ttfunk/encoded_string.rb +58 -4
- data/lib/ttfunk/max.rb +14 -0
- data/lib/ttfunk/min.rb +14 -0
- data/lib/ttfunk/one_based_array.rb +20 -0
- data/lib/ttfunk/otf_encoder.rb +5 -14
- data/lib/ttfunk/placeholder.rb +15 -1
- data/lib/ttfunk/reader.rb +6 -4
- data/lib/ttfunk/resource_file.rb +29 -5
- data/lib/ttfunk/sci_form.rb +20 -3
- data/lib/ttfunk/sub_table.rb +29 -4
- data/lib/ttfunk/subset/base.rb +48 -0
- data/lib/ttfunk/subset/code_page.rb +49 -2
- data/lib/ttfunk/subset/mac_roman.rb +2 -0
- data/lib/ttfunk/subset/unicode.rb +32 -0
- data/lib/ttfunk/subset/unicode_8bit.rb +32 -0
- data/lib/ttfunk/subset/windows_1252.rb +2 -0
- data/lib/ttfunk/subset.rb +8 -0
- data/lib/ttfunk/subset_collection.rb +39 -14
- data/lib/ttfunk/sum.rb +13 -0
- data/lib/ttfunk/table/cff/charset.rb +96 -18
- data/lib/ttfunk/table/cff/charsets/expert.rb +3 -2
- data/lib/ttfunk/table/cff/charsets/expert_subset.rb +3 -2
- data/lib/ttfunk/table/cff/charsets/iso_adobe.rb +3 -2
- data/lib/ttfunk/table/cff/charsets/standard_strings.rb +3 -2
- data/lib/ttfunk/table/cff/charsets.rb +1 -0
- data/lib/ttfunk/table/cff/charstring.rb +33 -12
- data/lib/ttfunk/table/cff/charstrings_index.rb +17 -11
- data/lib/ttfunk/table/cff/dict.rb +53 -23
- data/lib/ttfunk/table/cff/encoding.rb +82 -24
- data/lib/ttfunk/table/cff/encodings/expert.rb +3 -2
- data/lib/ttfunk/table/cff/encodings/standard.rb +3 -2
- data/lib/ttfunk/table/cff/encodings.rb +1 -0
- data/lib/ttfunk/table/cff/fd_selector.rb +61 -21
- data/lib/ttfunk/table/cff/font_dict.rb +30 -18
- data/lib/ttfunk/table/cff/font_index.rb +22 -10
- data/lib/ttfunk/table/cff/header.rb +16 -3
- data/lib/ttfunk/table/cff/index.rb +97 -65
- data/lib/ttfunk/table/cff/one_based_index.rb +11 -1
- data/lib/ttfunk/table/cff/path.rb +43 -4
- data/lib/ttfunk/table/cff/private_dict.rb +31 -11
- data/lib/ttfunk/table/cff/subr_index.rb +7 -2
- data/lib/ttfunk/table/cff/top_dict.rb +82 -59
- data/lib/ttfunk/table/cff/top_index.rb +10 -6
- data/lib/ttfunk/table/cff.rb +41 -21
- data/lib/ttfunk/table/cmap/format00.rb +27 -6
- data/lib/ttfunk/table/cmap/format04.rb +34 -14
- data/lib/ttfunk/table/cmap/format06.rb +28 -1
- data/lib/ttfunk/table/cmap/format10.rb +29 -2
- data/lib/ttfunk/table/cmap/format12.rb +29 -2
- data/lib/ttfunk/table/cmap/subtable.rb +50 -6
- data/lib/ttfunk/table/cmap.rb +21 -0
- data/lib/ttfunk/table/dsig.rb +47 -6
- data/lib/ttfunk/table/glyf/compound.rb +73 -6
- data/lib/ttfunk/table/glyf/path_based.rb +40 -3
- data/lib/ttfunk/table/glyf/simple.rb +50 -5
- data/lib/ttfunk/table/glyf.rb +15 -7
- data/lib/ttfunk/table/head.rb +84 -6
- data/lib/ttfunk/table/hhea.rb +71 -10
- data/lib/ttfunk/table/hmtx.rb +32 -5
- data/lib/ttfunk/table/kern/format0.rb +25 -7
- data/lib/ttfunk/table/kern.rb +16 -4
- data/lib/ttfunk/table/loca.rb +21 -8
- data/lib/ttfunk/table/maxp.rb +195 -10
- data/lib/ttfunk/table/name.rb +126 -9
- data/lib/ttfunk/table/os2.rb +150 -26
- data/lib/ttfunk/table/post/format10.rb +7 -0
- data/lib/ttfunk/table/post/format20.rb +9 -0
- data/lib/ttfunk/table/post/format30.rb +6 -0
- data/lib/ttfunk/table/post/format40.rb +5 -0
- data/lib/ttfunk/table/post.rb +63 -7
- data/lib/ttfunk/table/sbix.rb +50 -14
- data/lib/ttfunk/table/simple.rb +5 -0
- data/lib/ttfunk/table/vorg.rb +31 -3
- data/lib/ttfunk/table.rb +20 -1
- data/lib/ttfunk/ttf_encoder.rb +39 -41
- data/lib/ttfunk.rb +154 -1
- data.tar.gz.sig +0 -0
- metadata +50 -28
- metadata.gz.sig +0 -0
@@ -3,31 +3,41 @@
|
|
3
3
|
module TTFunk
|
4
4
|
class Table
|
5
5
|
class Cff < TTFunk::Table
|
6
|
+
# CFF top dict.
|
6
7
|
class TopDict < TTFunk::Table::Cff::Dict
|
8
|
+
# Default charstring type.
|
7
9
|
DEFAULT_CHARSTRING_TYPE = 2
|
10
|
+
|
11
|
+
# Length of placeholders for pointer operators.
|
8
12
|
POINTER_PLACEHOLDER_LENGTH = 5
|
13
|
+
|
14
|
+
# Length of placeholders for other operators.
|
9
15
|
PLACEHOLDER_LENGTH = 5
|
10
16
|
|
11
|
-
#
|
12
|
-
# of the file
|
17
|
+
# Operators whose values are offsets that point to other parts
|
18
|
+
# of the file.
|
13
19
|
POINTER_OPERATORS = {
|
14
20
|
charset: 15,
|
15
21
|
encoding: 16,
|
16
22
|
charstrings_index: 17,
|
17
23
|
private: 18,
|
18
24
|
font_index: 1236,
|
19
|
-
font_dict_selector: 1237
|
25
|
+
font_dict_selector: 1237,
|
20
26
|
}.freeze
|
21
27
|
|
22
|
-
#
|
28
|
+
# All the operators we currently care about.
|
23
29
|
OPERATORS = {
|
24
30
|
**POINTER_OPERATORS,
|
25
31
|
ros: 1230,
|
26
|
-
charstring_type: 1206
|
32
|
+
charstring_type: 1206,
|
27
33
|
}.freeze
|
28
34
|
|
35
|
+
# Inverse operator mapping.
|
29
36
|
OPERATOR_CODES = OPERATORS.invert
|
30
37
|
|
38
|
+
# Encode dict.
|
39
|
+
#
|
40
|
+
# @return [TTFunk::EncodedString]
|
31
41
|
def encode(*)
|
32
42
|
EncodedString.new do |result|
|
33
43
|
each_with_index do |(operator, operands), _idx|
|
@@ -36,7 +46,7 @@ module TTFunk
|
|
36
46
|
elsif pointer_operator?(operator)
|
37
47
|
result << Placeholder.new(
|
38
48
|
OPERATOR_CODES[operator],
|
39
|
-
length: POINTER_PLACEHOLDER_LENGTH
|
49
|
+
length: POINTER_PLACEHOLDER_LENGTH,
|
40
50
|
)
|
41
51
|
else
|
42
52
|
operands.each { |operand| result << encode_operand(operand) }
|
@@ -47,75 +57,69 @@ module TTFunk
|
|
47
57
|
end
|
48
58
|
end
|
49
59
|
|
50
|
-
|
60
|
+
# Finalize the table.
|
61
|
+
#
|
62
|
+
# @param new_cff_data [TTFunk::EncodedString]
|
63
|
+
# @param charmap [Hash{Integer => Hash}] keys are the charac codes,
|
64
|
+
# values are hashes:
|
65
|
+
# * `:old` (<tt>Integer</tt>) - glyph ID in the original font.
|
66
|
+
# * `:new` (<tt>Integer</tt>) - glyph ID in the subset font.
|
67
|
+
# @return [void]
|
68
|
+
def finalize(new_cff_data, charmap)
|
51
69
|
if charset
|
52
|
-
finalize_subtable(
|
53
|
-
new_cff_data, :charset, charset.encode(new_to_old)
|
54
|
-
)
|
70
|
+
finalize_subtable(new_cff_data, :charset, charset.encode(charmap))
|
55
71
|
end
|
56
72
|
|
57
73
|
if encoding
|
58
|
-
finalize_subtable(
|
59
|
-
new_cff_data, :encoding, encoding.encode(new_to_old, old_to_new)
|
60
|
-
)
|
74
|
+
finalize_subtable(new_cff_data, :encoding, encoding.encode(charmap))
|
61
75
|
end
|
62
76
|
|
63
77
|
if charstrings_index
|
64
|
-
finalize_subtable(
|
65
|
-
new_cff_data,
|
66
|
-
:charstrings_index,
|
67
|
-
charstrings_index.encode(new_to_old, &:encode)
|
68
|
-
)
|
78
|
+
finalize_subtable(new_cff_data, :charstrings_index, charstrings_index.encode(charmap))
|
69
79
|
end
|
70
80
|
|
71
81
|
if font_index
|
72
|
-
finalize_subtable(
|
73
|
-
new_cff_data,
|
74
|
-
:font_index,
|
75
|
-
font_index.encode do |font_dict|
|
76
|
-
font_dict.encode(new_to_old)
|
77
|
-
end
|
78
|
-
)
|
82
|
+
finalize_subtable(new_cff_data, :font_index, font_index.encode)
|
79
83
|
|
80
|
-
font_index.finalize(new_cff_data
|
84
|
+
font_index.finalize(new_cff_data)
|
81
85
|
end
|
82
86
|
|
83
87
|
if font_dict_selector
|
84
|
-
finalize_subtable(
|
85
|
-
new_cff_data,
|
86
|
-
:font_dict_selector,
|
87
|
-
font_dict_selector.encode(new_to_old)
|
88
|
-
)
|
88
|
+
finalize_subtable(new_cff_data, :font_dict_selector, font_dict_selector.encode(charmap))
|
89
89
|
end
|
90
90
|
|
91
91
|
if private_dict
|
92
|
-
encoded_private_dict = private_dict.encode
|
92
|
+
encoded_private_dict = private_dict.encode
|
93
93
|
encoded_offset = encode_integer32(new_cff_data.length)
|
94
94
|
encoded_length = encode_integer32(encoded_private_dict.length)
|
95
95
|
|
96
|
-
new_cff_data.resolve_placeholder(
|
97
|
-
|
98
|
-
)
|
99
|
-
|
100
|
-
new_cff_data.resolve_placeholder(
|
101
|
-
:"private_offset_#{@table_offset}", encoded_offset
|
102
|
-
)
|
96
|
+
new_cff_data.resolve_placeholder(:"private_length_#{@table_offset}", encoded_length)
|
97
|
+
new_cff_data.resolve_placeholder(:"private_offset_#{@table_offset}", encoded_offset)
|
103
98
|
|
104
99
|
private_dict.finalize(encoded_private_dict)
|
105
100
|
new_cff_data << encoded_private_dict
|
106
101
|
end
|
107
102
|
end
|
108
103
|
|
104
|
+
# Registry Ordering Supplement.
|
105
|
+
#
|
106
|
+
# @return [Array(Integer, Integer, Integer), nil]
|
109
107
|
def ros
|
110
108
|
self[OPERATORS[:ros]]
|
111
109
|
end
|
112
110
|
|
111
|
+
# Is Registry Ordering Supplement present in this dict?
|
112
|
+
#
|
113
|
+
# @return [Boolean]
|
113
114
|
def ros?
|
114
115
|
!ros.nil?
|
115
116
|
end
|
116
117
|
|
117
118
|
alias is_cid_font? ros?
|
118
119
|
|
120
|
+
# Charset specified in this dict.
|
121
|
+
#
|
122
|
+
# @return [TTFunk::Table::Cff::Charset, nil]
|
119
123
|
def charset
|
120
124
|
@charset ||=
|
121
125
|
if (charset_offset_or_id = self[OPERATORS[:charset]])
|
@@ -127,38 +131,47 @@ module TTFunk
|
|
127
131
|
end
|
128
132
|
end
|
129
133
|
|
134
|
+
# Encoding specified in this dict.
|
135
|
+
#
|
136
|
+
# @return [TTFunk::Table::Cff::Encoding, nil]
|
130
137
|
def encoding
|
138
|
+
# PostScript type 1 fonts, i.e. CID fonts, i.e. some fonts that use
|
139
|
+
# the CFF table, don't specify an encoding, so this can be nil
|
131
140
|
@encoding ||=
|
132
|
-
|
133
|
-
|
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
|
141
|
+
if (encoding_offset_or_id = self[OPERATORS[:encoding]])
|
142
|
+
Encoding.new(self, file, encoding_offset_or_id.first)
|
138
143
|
end
|
139
144
|
end
|
140
145
|
|
141
|
-
#
|
146
|
+
# Charstrings index specified in this dict.
|
147
|
+
#
|
148
|
+
# > OpenType fonts with TrueType outlines use a glyph index to specify
|
149
|
+
# and access glyphs within a font; e.g., to index within the `loca`
|
150
|
+
# table and thereby access glyph data in the `glyf` table. This
|
151
|
+
# concept is retained in OpenType CFF fonts, except that glyph data is
|
152
|
+
# accessed through the CharStrings INDEX of the CFF table.
|
153
|
+
#
|
154
|
+
# > --- [CFF — Compact Font Format Table](https://www.microsoft.com/typography/otspec/cff.htm)
|
142
155
|
#
|
143
|
-
#
|
144
|
-
# and access glyphs within a font; e.g., to index within the 'loca'
|
145
|
-
# table and thereby access glyph data in the 'glyf' table. This concept
|
146
|
-
# is retained in OpenType CFF fonts, except that glyph data is accessed
|
147
|
-
# through the CharStrings INDEX of the CFF table."
|
156
|
+
# @return [TTFunk::Table::Cff::CharstringsIndex, nil]
|
148
157
|
def charstrings_index
|
149
158
|
@charstrings_index ||=
|
150
159
|
if (charstrings_offset = self[OPERATORS[:charstrings_index]])
|
151
|
-
CharstringsIndex.new(
|
152
|
-
self, file, cff_offset + charstrings_offset.first
|
153
|
-
)
|
160
|
+
CharstringsIndex.new(self, file, cff_offset + charstrings_offset.first)
|
154
161
|
end
|
155
162
|
end
|
156
163
|
|
164
|
+
# Charstring type specified in this dict.
|
165
|
+
#
|
166
|
+
# @return [Integer]
|
157
167
|
def charstring_type
|
158
168
|
@charstring_type =
|
159
169
|
self[OPERATORS[:charstring_type]] || DEFAULT_CHARSTRING_TYPE
|
160
170
|
end
|
161
171
|
|
172
|
+
# Font index specified in this dict.
|
173
|
+
#
|
174
|
+
# @return [TTFunk::Table::Cff::FontIndex, nil]
|
162
175
|
def font_index
|
163
176
|
@font_index ||=
|
164
177
|
if (font_index_offset = self[OPERATORS[:font_index]])
|
@@ -166,6 +179,9 @@ module TTFunk
|
|
166
179
|
end
|
167
180
|
end
|
168
181
|
|
182
|
+
# Font dict selector specified in this dict.
|
183
|
+
#
|
184
|
+
# @return [TTFunk::Table::Cff::FdSelector, nil]
|
169
185
|
def font_dict_selector
|
170
186
|
@font_dict_selector ||=
|
171
187
|
if (fd_select_offset = self[OPERATORS[:font_dict_selector]])
|
@@ -173,21 +189,28 @@ module TTFunk
|
|
173
189
|
end
|
174
190
|
end
|
175
191
|
|
192
|
+
# Private dict specified in this dict.
|
193
|
+
#
|
194
|
+
# @return [TTFunk::Table::Cff::PrivateDict, nil]
|
176
195
|
def private_dict
|
177
196
|
@private_dict ||=
|
178
197
|
if (info = self[OPERATORS[:private]])
|
179
198
|
private_dict_length, private_dict_offset = info
|
180
199
|
|
181
|
-
PrivateDict.new(
|
182
|
-
file, cff_offset + private_dict_offset, private_dict_length
|
183
|
-
)
|
200
|
+
PrivateDict.new(file, cff_offset + private_dict_offset, private_dict_length)
|
184
201
|
end
|
185
202
|
end
|
186
203
|
|
204
|
+
# CFF table in this file.
|
205
|
+
#
|
206
|
+
# @return [TTFunk::Table::Cff]
|
187
207
|
def cff
|
188
208
|
file.cff
|
189
209
|
end
|
190
210
|
|
211
|
+
# Ofsset of CFF table in the file.
|
212
|
+
#
|
213
|
+
# @return [Integer]
|
191
214
|
def cff_offset
|
192
215
|
cff.offset
|
193
216
|
end
|
@@ -198,12 +221,12 @@ module TTFunk
|
|
198
221
|
EncodedString.new do |result|
|
199
222
|
result << Placeholder.new(
|
200
223
|
:"private_length_#{@table_offset}",
|
201
|
-
length: PLACEHOLDER_LENGTH
|
224
|
+
length: PLACEHOLDER_LENGTH,
|
202
225
|
)
|
203
226
|
|
204
227
|
result << Placeholder.new(
|
205
228
|
:"private_offset_#{@table_offset}",
|
206
|
-
length: PLACEHOLDER_LENGTH
|
229
|
+
length: PLACEHOLDER_LENGTH,
|
207
230
|
)
|
208
231
|
end
|
209
232
|
end
|
@@ -3,13 +3,17 @@
|
|
3
3
|
module TTFunk
|
4
4
|
class Table
|
5
5
|
class Cff < TTFunk::Table
|
6
|
+
# CFF Index conatining Top dict.
|
6
7
|
class TopIndex < TTFunk::Table::Cff::Index
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
8
|
+
private
|
9
|
+
|
10
|
+
def decode_item(_index, offset, length)
|
11
|
+
TTFunk::Table::Cff::TopDict.new(file, offset, length)
|
12
|
+
end
|
13
|
+
|
14
|
+
def encode_items(*)
|
15
|
+
# Re-encode the top dict
|
16
|
+
map(&:encode)
|
13
17
|
end
|
14
18
|
end
|
15
19
|
end
|
data/lib/ttfunk/table/cff.rb
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
module TTFunk
|
4
4
|
class Table
|
5
|
+
# Compact Font Format (`CFF `) table
|
5
6
|
class Cff < TTFunk::Table
|
6
7
|
autoload :Charset, 'ttfunk/table/cff/charset'
|
7
8
|
autoload :Charsets, 'ttfunk/table/cff/charsets'
|
@@ -22,27 +23,55 @@ module TTFunk
|
|
22
23
|
autoload :TopDict, 'ttfunk/table/cff/top_dict'
|
23
24
|
autoload :TopIndex, 'ttfunk/table/cff/top_index'
|
24
25
|
|
25
|
-
|
26
|
+
# Table tag. The extra space is important.
|
27
|
+
TAG = 'CFF '
|
26
28
|
|
27
|
-
|
29
|
+
# Table header.
|
30
|
+
# @return [TTFunk::Table::Cff::Header]
|
31
|
+
attr_reader :header
|
32
|
+
|
33
|
+
# Name index.
|
34
|
+
# @return [TTFunk::Table::Cff::Index]
|
35
|
+
attr_reader :name_index
|
36
|
+
|
37
|
+
# Top dict index.
|
38
|
+
# @return [TTFunk::Table::Cff::TopIndex]
|
39
|
+
attr_reader :top_index
|
40
|
+
|
41
|
+
# Strings index.
|
42
|
+
# @return [TTFunk::Table::Cff::OneBasedIndex]
|
43
|
+
attr_reader :string_index
|
44
|
+
|
45
|
+
# Global subroutine index.
|
46
|
+
# @return [TTFunk::Table::Cff::SubrIndex]
|
28
47
|
attr_reader :global_subr_index
|
29
48
|
|
49
|
+
# Table tag.
|
50
|
+
# @return [String]
|
30
51
|
def tag
|
31
52
|
TAG
|
32
53
|
end
|
33
54
|
|
34
|
-
|
55
|
+
# Encode table.
|
56
|
+
#
|
57
|
+
# @param subset [TTFunk::Subset::MacRoman, TTFunk::Subset::Windows1252,
|
58
|
+
# TTFunk::Subset::Unicode, TTFunk::Subset::Unicode8Bit]
|
59
|
+
# @return [TTFunk::EncodedString]
|
60
|
+
def encode(subset)
|
61
|
+
# Make sure TopDict has an entry for encoding so it could be properly replaced
|
62
|
+
top_index[0][TopDict::OPERATORS[:encoding]] = 0
|
63
|
+
|
35
64
|
EncodedString.new do |result|
|
36
|
-
|
65
|
+
result.concat(
|
37
66
|
header.encode,
|
38
67
|
name_index.encode,
|
39
|
-
top_index.encode
|
68
|
+
top_index.encode,
|
40
69
|
string_index.encode,
|
41
|
-
global_subr_index.encode
|
42
|
-
|
70
|
+
global_subr_index.encode,
|
71
|
+
)
|
43
72
|
|
44
|
-
|
45
|
-
top_index[0].finalize(result,
|
73
|
+
charmap = subset.new_cmap_table[:charmap]
|
74
|
+
top_index[0].finalize(result, charmap)
|
46
75
|
end
|
47
76
|
end
|
48
77
|
|
@@ -51,18 +80,9 @@ module TTFunk
|
|
51
80
|
def parse!
|
52
81
|
@header = Header.new(file, offset)
|
53
82
|
@name_index = Index.new(file, @header.table_offset + @header.length)
|
54
|
-
|
55
|
-
@
|
56
|
-
|
57
|
-
)
|
58
|
-
|
59
|
-
@string_index = OneBasedIndex.new(
|
60
|
-
file, @top_index.table_offset + @top_index.length
|
61
|
-
)
|
62
|
-
|
63
|
-
@global_subr_index = SubrIndex.new(
|
64
|
-
file, @string_index.table_offset + @string_index.length
|
65
|
-
)
|
83
|
+
@top_index = TopIndex.new(file, @name_index.table_offset + @name_index.length)
|
84
|
+
@string_index = OneBasedIndex.new(file, @top_index.table_offset + @top_index.length)
|
85
|
+
@global_subr_index = SubrIndex.new(file, @string_index.table_offset + @string_index.length)
|
66
86
|
end
|
67
87
|
end
|
68
88
|
end
|
@@ -3,16 +3,30 @@
|
|
3
3
|
module TTFunk
|
4
4
|
class Table
|
5
5
|
class Cmap
|
6
|
+
# Format 0: Byte encoding table.
|
7
|
+
#
|
8
|
+
# This module conditionally extends {TTFunk::Table::Cmap::Subtable}.
|
6
9
|
module Format00
|
10
|
+
# Language.
|
11
|
+
# @return [Integer]
|
7
12
|
attr_reader :language
|
13
|
+
|
14
|
+
# Code map.
|
15
|
+
# @return [Array<Integer>]
|
8
16
|
attr_reader :code_map
|
9
17
|
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
18
|
+
# Encode the encoding record to format 0.
|
19
|
+
#
|
20
|
+
# @param charmap [Hash{Integer => Integer}] a hash mapping character
|
21
|
+
# codes to glyph ids (where the glyph ids are from the original font).
|
22
|
+
# @return [Hash]
|
23
|
+
# * `:charmap` (<tt>Hash{Integer => Hash}</tt>) keys are the characrers in
|
24
|
+
# `charset`, values are hashes:
|
25
|
+
# * `:old` (<tt>Integer</tt>) - glyph ID in the original font.
|
26
|
+
# * `:new` (<tt>Integer</tt>) - glyph ID in the subset font.
|
27
|
+
# that maps the characters in charmap to a
|
28
|
+
# * `:subtable` (<tt>String</tt>) - serialized encoding record.
|
29
|
+
# * `:max_glyph_id` (<tt>Integer</tt>) - maximum glyph ID in the new font.
|
16
30
|
def self.encode(charmap)
|
17
31
|
next_id = 0
|
18
32
|
glyph_indexes = Array.new(256, 0)
|
@@ -32,10 +46,17 @@ module TTFunk
|
|
32
46
|
{ charmap: new_map, subtable: subtable, max_glyph_id: next_id + 1 }
|
33
47
|
end
|
34
48
|
|
49
|
+
# Get glyph ID for character code.
|
50
|
+
#
|
51
|
+
# @param code [Integer] character code.
|
52
|
+
# @return [Integer] glyph ID.
|
35
53
|
def [](code)
|
36
54
|
@code_map[code] || 0
|
37
55
|
end
|
38
56
|
|
57
|
+
# Is this encoding record format supported?
|
58
|
+
#
|
59
|
+
# @return [true]
|
39
60
|
def supported?
|
40
61
|
true
|
41
62
|
end
|
@@ -3,16 +3,30 @@
|
|
3
3
|
module TTFunk
|
4
4
|
class Table
|
5
5
|
class Cmap
|
6
|
+
# Format 4: Segment mapping to delta values.
|
7
|
+
#
|
8
|
+
# This module conditionally extends {TTFunk::Table::Cmap::Subtable}.
|
6
9
|
module Format04
|
10
|
+
# Language.
|
11
|
+
# @return [Integer]
|
7
12
|
attr_reader :language
|
13
|
+
|
14
|
+
# Code map.
|
15
|
+
# @return [Hash{Integer => Integer}]
|
8
16
|
attr_reader :code_map
|
9
17
|
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
15
|
-
#
|
18
|
+
# Encode the encoding record to format 4.
|
19
|
+
#
|
20
|
+
# @param charmap [Hash{Integer => Integer}] a hash mapping character
|
21
|
+
# codes to glyph IDs from the original font.
|
22
|
+
# @return [Hash]
|
23
|
+
# * `:charmap` (<tt>Hash{Integer => Hash}</tt>) keys are the characrers in
|
24
|
+
# `charset`, values are hashes:
|
25
|
+
# * `:old` (<tt>Integer</tt>) - glyph ID in the original font.
|
26
|
+
# * `:new` (<tt>Integer</tt>) - glyph ID in the subset font.
|
27
|
+
# that maps the characters in charmap to a
|
28
|
+
# * `:subtable` (<tt>String</tt>) - serialized encoding record.
|
29
|
+
# * `:max_glyph_id` (<tt>Integer</tt>) - maximum glyph ID in the new font.
|
16
30
|
def self.encode(charmap)
|
17
31
|
end_codes = []
|
18
32
|
start_codes = []
|
@@ -63,10 +77,10 @@ module TTFunk
|
|
63
77
|
|
64
78
|
if a - start_glyph_id >= 0x8000
|
65
79
|
deltas << 0
|
66
|
-
range_offsets << 2 * (glyph_indices.length + segcount - segment)
|
80
|
+
range_offsets << (2 * (glyph_indices.length + segcount - segment))
|
67
81
|
a.upto(b) { |code| glyph_indices << new_map[code][:new] }
|
68
82
|
else
|
69
|
-
deltas << -a + start_glyph_id
|
83
|
+
deltas << (-a + start_glyph_id)
|
70
84
|
range_offsets << 0
|
71
85
|
end
|
72
86
|
|
@@ -75,14 +89,14 @@ module TTFunk
|
|
75
89
|
|
76
90
|
# format, length, language
|
77
91
|
subtable = [
|
78
|
-
4, 16 + 8 * segcount + 2 * glyph_indices.length, 0
|
92
|
+
4, 16 + (8 * segcount) + (2 * glyph_indices.length), 0,
|
79
93
|
].pack('nnn')
|
80
94
|
|
81
|
-
search_range = 2 * 2**(Math.log(segcount) / Math.log(2))
|
82
|
-
entry_selector = (Math.log(search_range / 2) / Math.log(2))
|
95
|
+
search_range = 2 * (2**Integer(Math.log(segcount) / Math.log(2)))
|
96
|
+
entry_selector = Integer(Math.log(search_range / 2) / Math.log(2))
|
83
97
|
range_shift = (2 * segcount) - search_range
|
84
98
|
subtable << [
|
85
|
-
segcount * 2, search_range, entry_selector, range_shift
|
99
|
+
segcount * 2, search_range, entry_selector, range_shift,
|
86
100
|
].pack('nnnn')
|
87
101
|
|
88
102
|
subtable << end_codes.pack('n*') << "\0\0" << start_codes.pack('n*')
|
@@ -92,10 +106,17 @@ module TTFunk
|
|
92
106
|
{ charmap: new_map, subtable: subtable, max_glyph_id: next_id + 1 }
|
93
107
|
end
|
94
108
|
|
109
|
+
# Get glyph ID for character code.
|
110
|
+
#
|
111
|
+
# @param code [Integer] character code.
|
112
|
+
# @return [Integer] glyph ID.
|
95
113
|
def [](code)
|
96
114
|
@code_map[code] || 0
|
97
115
|
end
|
98
116
|
|
117
|
+
# Is this encoding record format supported?
|
118
|
+
#
|
119
|
+
# @return [true]
|
99
120
|
def supported?
|
100
121
|
true
|
101
122
|
end
|
@@ -123,8 +144,7 @@ module TTFunk
|
|
123
144
|
if (id_range_offset[i]).zero?
|
124
145
|
glyph_id = code + id_delta[i]
|
125
146
|
else
|
126
|
-
index = id_range_offset[i] / 2 +
|
127
|
-
(code - start_code[i]) - (segcount - i)
|
147
|
+
index = (id_range_offset[i] / 2) + (code - start_code[i]) - (segcount - i)
|
128
148
|
# Because some TTF fonts are broken
|
129
149
|
glyph_id = glyph_ids[index] || 0
|
130
150
|
glyph_id += id_delta[i] if glyph_id != 0
|
@@ -3,10 +3,30 @@
|
|
3
3
|
module TTFunk
|
4
4
|
class Table
|
5
5
|
class Cmap
|
6
|
+
# Format 6: Trimmed table mapping.
|
7
|
+
#
|
8
|
+
# This module conditionally extends {TTFunk::Table::Cmap::Subtable}.
|
6
9
|
module Format06
|
10
|
+
# Language.
|
11
|
+
# @return [Integer]
|
7
12
|
attr_reader :language
|
13
|
+
|
14
|
+
# Code map.
|
15
|
+
# @return [Hash{Integer => Integer}]
|
8
16
|
attr_reader :code_map
|
9
17
|
|
18
|
+
# Encode the encoding record to format 6.
|
19
|
+
#
|
20
|
+
# @param charmap [Hash{Integer => Integer}] a hash mapping character
|
21
|
+
# codes to glyph IDs from the original font.
|
22
|
+
# @return [Hash]
|
23
|
+
# * `:charmap` (<tt>Hash{Integer => Hash}</tt>) keys are the characrers in
|
24
|
+
# `charset`, values are hashes:
|
25
|
+
# * `:old` (<tt>Integer</tt>) - glyph ID in the original font.
|
26
|
+
# * `:new` (<tt>Integer</tt>) - glyph ID in the subset font.
|
27
|
+
# that maps the characters in charmap to a
|
28
|
+
# * `:subtable` (<tt>String</tt>) - serialized encoding record.
|
29
|
+
# * `:max_glyph_id` (<tt>Integer</tt>) - maximum glyph ID in the new font.
|
10
30
|
def self.encode(charmap)
|
11
31
|
next_id = 0
|
12
32
|
glyph_map = { 0 => 0 }
|
@@ -25,16 +45,23 @@ module TTFunk
|
|
25
45
|
end
|
26
46
|
|
27
47
|
subtable = [
|
28
|
-
6, 10 + entry_count * 2, 0, low_char, entry_count, *glyph_indexes
|
48
|
+
6, 10 + (entry_count * 2), 0, low_char, entry_count, *glyph_indexes,
|
29
49
|
].pack('n*')
|
30
50
|
|
31
51
|
{ charmap: new_map, subtable: subtable, max_glyph_id: next_id + 1 }
|
32
52
|
end
|
33
53
|
|
54
|
+
# Get glyph ID for character code.
|
55
|
+
#
|
56
|
+
# @param code [Integer] character code.
|
57
|
+
# @return [Integer] glyph ID.
|
34
58
|
def [](code)
|
35
59
|
@code_map[code] || 0
|
36
60
|
end
|
37
61
|
|
62
|
+
# Is this encoding record format supported?
|
63
|
+
#
|
64
|
+
# @return [true]
|
38
65
|
def supported?
|
39
66
|
true
|
40
67
|
end
|
@@ -3,10 +3,30 @@
|
|
3
3
|
module TTFunk
|
4
4
|
class Table
|
5
5
|
class Cmap
|
6
|
+
# Format 10: Trimmed array.
|
7
|
+
#
|
8
|
+
# This module conditionally extends {TTFunk::Table::Cmap::Subtable}.
|
6
9
|
module Format10
|
10
|
+
# Language.
|
11
|
+
# @return [Integer]
|
7
12
|
attr_reader :language
|
13
|
+
|
14
|
+
# Code map.
|
15
|
+
# @return [Hash{Integer => Integer}]
|
8
16
|
attr_reader :code_map
|
9
17
|
|
18
|
+
# Encode the encoding record to format 10.
|
19
|
+
#
|
20
|
+
# @param charmap [Hash{Integer => Integer}] a hash mapping character
|
21
|
+
# codes to glyph IDs from the original font.
|
22
|
+
# @return [Hash]
|
23
|
+
# * `:charmap` (<tt>Hash{Integer => Hash}</tt>) keys are the characrers in
|
24
|
+
# `charset`, values are hashes:
|
25
|
+
# * `:old` (<tt>Integer</tt>) - glyph ID in the original font.
|
26
|
+
# * `:new` (<tt>Integer</tt>) - glyph ID in the subset font.
|
27
|
+
# that maps the characters in charmap to a
|
28
|
+
# * `:subtable` (<tt>String</tt>) - serialized encoding record.
|
29
|
+
# * `:max_glyph_id` (<tt>Integer</tt>) - maximum glyph ID in the new font.
|
10
30
|
def self.encode(charmap)
|
11
31
|
next_id = 0
|
12
32
|
glyph_map = { 0 => 0 }
|
@@ -25,17 +45,24 @@ module TTFunk
|
|
25
45
|
end
|
26
46
|
|
27
47
|
subtable = [
|
28
|
-
10, 0, 20 + entry_count * 4, 0, low_char, entry_count,
|
29
|
-
*glyph_indexes
|
48
|
+
10, 0, 20 + (entry_count * 4), 0, low_char, entry_count,
|
49
|
+
*glyph_indexes,
|
30
50
|
].pack('nnN*')
|
31
51
|
|
32
52
|
{ charmap: new_map, subtable: subtable, max_glyph_id: next_id + 1 }
|
33
53
|
end
|
34
54
|
|
55
|
+
# Get glyph ID for character code.
|
56
|
+
#
|
57
|
+
# @param code [Integer] character code.
|
58
|
+
# @return [Integer] glyph ID.
|
35
59
|
def [](code)
|
36
60
|
@code_map[code] || 0
|
37
61
|
end
|
38
62
|
|
63
|
+
# Is this encoding record format supported?
|
64
|
+
#
|
65
|
+
# @return [true]
|
39
66
|
def supported?
|
40
67
|
true
|
41
68
|
end
|