ttfunk 1.7.0 → 1.8.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 +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,26 +3,48 @@
|
|
3
3
|
require_relative 'subset'
|
4
4
|
|
5
5
|
module TTFunk
|
6
|
+
# Subset collection.
|
7
|
+
#
|
8
|
+
# For many use cases a font subset can be efficiently encoded using MacRoman
|
9
|
+
# encoding. However, for full font coverage and characters that are not in
|
10
|
+
# MacRoman encoding an additional Unicode subset is used. There can be as many
|
11
|
+
# as needed Unicode subsets to fully cover glyphs provided by the original
|
12
|
+
# font. Ther resulting set of subsets all use 8-bit encoding helping to
|
13
|
+
# efficiently encode text in Prawn.
|
6
14
|
class SubsetCollection
|
15
|
+
# @param original [TTFunk::File]
|
7
16
|
def initialize(original)
|
8
17
|
@original = original
|
9
18
|
@subsets = [Subset.for(@original, :mac_roman)]
|
10
19
|
end
|
11
20
|
|
21
|
+
# Get subset by index.
|
22
|
+
#
|
23
|
+
# @param subset [Integer]
|
24
|
+
# @return [TTFunk::Subset::Unicode, TTFunk::Subset::Unicode8Bit,
|
25
|
+
# TTFunk::Subset::MacRoman, TTFunk::Subset::Windows1252]
|
12
26
|
def [](subset)
|
13
27
|
@subsets[subset]
|
14
28
|
end
|
15
29
|
|
16
|
-
#
|
30
|
+
# Add chracters to appropiate subsets.
|
31
|
+
#
|
32
|
+
# @param characters [Array<Integer>] should be an array of UTF-16 code
|
33
|
+
# points
|
34
|
+
# @return [void]
|
17
35
|
def use(characters)
|
18
36
|
characters.each do |char|
|
19
37
|
covered = false
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
subset
|
24
|
-
|
25
|
-
|
38
|
+
i = 0
|
39
|
+
length = @subsets.length
|
40
|
+
while i < length
|
41
|
+
subset = @subsets[i]
|
42
|
+
if subset.covers?(char)
|
43
|
+
subset.use(char)
|
44
|
+
covered = true
|
45
|
+
break
|
46
|
+
end
|
47
|
+
i += 1
|
26
48
|
end
|
27
49
|
|
28
50
|
unless covered
|
@@ -32,13 +54,16 @@ module TTFunk
|
|
32
54
|
end
|
33
55
|
end
|
34
56
|
|
35
|
-
#
|
36
|
-
#
|
37
|
-
#
|
38
|
-
#
|
39
|
-
#
|
40
|
-
#
|
41
|
-
#
|
57
|
+
# Encode characters into subset-character pairs.
|
58
|
+
#
|
59
|
+
# @param characters [Array<Integer>] should be an array of UTF-16 code
|
60
|
+
# points
|
61
|
+
# @return [Array<Array(Integer, String)>] subset chunks, where each chunk
|
62
|
+
# is another array of two elements. The first element is the subset
|
63
|
+
# number, and the second element is the string of characters to render
|
64
|
+
# with that font subset. The strings will be encoded for their subset
|
65
|
+
# font, and so may not look (in the raw) like what was passed in, but they
|
66
|
+
# will render correctly with the corresponding subset font.
|
42
67
|
def encode(characters)
|
43
68
|
return [] if characters.empty?
|
44
69
|
|
data/lib/ttfunk/sum.rb
CHANGED
@@ -1,18 +1,31 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module TTFunk
|
4
|
+
# Sum aggreaget. Is sums all pushed values.
|
4
5
|
class Sum < Aggregate
|
6
|
+
# Value
|
7
|
+
#
|
8
|
+
# @return [#+]
|
5
9
|
attr_reader :value
|
6
10
|
|
11
|
+
# @param init_value [#+] initial value
|
7
12
|
def initialize(init_value = 0)
|
8
13
|
super()
|
9
14
|
@value = init_value
|
10
15
|
end
|
11
16
|
|
17
|
+
# Push a value. It will be added to the current value.
|
18
|
+
#
|
19
|
+
# @param operand [any]
|
20
|
+
# @return [void]
|
12
21
|
def <<(operand)
|
13
22
|
@value += coerce(operand)
|
14
23
|
end
|
15
24
|
|
25
|
+
# Get the stored value or default.
|
26
|
+
#
|
27
|
+
# @param _default [any] Unused. Here for API compatibility.
|
28
|
+
# @return [any]
|
16
29
|
def value_or(_default)
|
17
30
|
# value should always be non-nil
|
18
31
|
value
|
@@ -3,25 +3,47 @@
|
|
3
3
|
module TTFunk
|
4
4
|
class Table
|
5
5
|
class Cff < TTFunk::Table
|
6
|
+
# CFF Charset
|
6
7
|
class Charset < TTFunk::SubTable
|
7
8
|
include Enumerable
|
8
9
|
|
10
|
+
# First glyph string. This is an implicit glyph present in all charsets.
|
9
11
|
FIRST_GLYPH_STRING = '.notdef'
|
12
|
+
|
13
|
+
# Format 0.
|
10
14
|
ARRAY_FORMAT = 0
|
15
|
+
|
16
|
+
# Format 1.
|
11
17
|
RANGE_FORMAT_8 = 1
|
18
|
+
|
19
|
+
# Format 2.
|
12
20
|
RANGE_FORMAT_16 = 2
|
13
21
|
|
22
|
+
# Predefined ISOAdobe charset ID.
|
14
23
|
ISO_ADOBE_CHARSET_ID = 0
|
24
|
+
|
25
|
+
# Predefined Expert charset ID.
|
15
26
|
EXPERT_CHARSET_ID = 1
|
27
|
+
|
28
|
+
# Predefined Expert Subset charset ID.
|
16
29
|
EXPERT_SUBSET_CHARSET_ID = 2
|
17
30
|
|
31
|
+
# Default charset ID.
|
18
32
|
DEFAULT_CHARSET_ID = ISO_ADOBE_CHARSET_ID
|
19
33
|
|
20
34
|
class << self
|
35
|
+
# Standard strings defined in the spec that do not need to be defined
|
36
|
+
# in the CFF.
|
37
|
+
#
|
38
|
+
# @return [TTFunk::OneBasedArray<String>]
|
21
39
|
def standard_strings
|
22
40
|
Charsets::STANDARD_STRINGS
|
23
41
|
end
|
24
42
|
|
43
|
+
# Strings for charset ID.
|
44
|
+
#
|
45
|
+
# @param charset_id [Integer]
|
46
|
+
# @return [TTFunk::OneBasedArray<String>]
|
25
47
|
def strings_for_charset_id(charset_id)
|
26
48
|
case charset_id
|
27
49
|
when ISO_ADOBE_CHARSET_ID
|
@@ -34,9 +56,39 @@ module TTFunk
|
|
34
56
|
end
|
35
57
|
end
|
36
58
|
|
37
|
-
|
38
|
-
|
39
|
-
|
59
|
+
# Encoded entries.
|
60
|
+
# @return [TTFunk::OneBasedArray<Integer>, Array<Range<Integer>>]
|
61
|
+
attr_reader :entries
|
62
|
+
|
63
|
+
# Length of encoded charset subtable.
|
64
|
+
# @return [Integer]
|
65
|
+
attr_reader :length
|
66
|
+
|
67
|
+
# Top dict.
|
68
|
+
# @return [TTFunk::Table::Cff::TopDict]
|
69
|
+
attr_reader :top_dict
|
70
|
+
|
71
|
+
# Encodign format.
|
72
|
+
# @return [Integer]
|
73
|
+
attr_reader :format
|
74
|
+
|
75
|
+
# Number of encoded items.
|
76
|
+
# @return [Integer]
|
77
|
+
attr_reader :items_count
|
78
|
+
|
79
|
+
# Offset or charset ID.
|
80
|
+
# @return [Integer]
|
81
|
+
attr_reader :offset_or_id
|
82
|
+
|
83
|
+
# @overload initialize(top_dict, file, offset = nil, length = nil)
|
84
|
+
# @param top_dict [TTFunk::Table:Cff::TopDict]
|
85
|
+
# @param file [TTFunk::File]
|
86
|
+
# @param offset [Integer]
|
87
|
+
# @param length [Integer]
|
88
|
+
# @overload initialize(top_dict, file, charset_id)
|
89
|
+
# @param top_dict [TTFunk::Table:Cff::TopDict]
|
90
|
+
# @param file [TTFunk::File]
|
91
|
+
# @param charset_id [Integer] 0, 1, or 2
|
40
92
|
def initialize(top_dict, file, offset_or_id = nil, length = nil)
|
41
93
|
@top_dict = top_dict
|
42
94
|
@offset_or_id = offset_or_id || DEFAULT_CHARSET_ID
|
@@ -44,23 +96,37 @@ module TTFunk
|
|
44
96
|
if offset
|
45
97
|
super(file, offset, length)
|
46
98
|
else
|
47
|
-
@
|
99
|
+
@items_count = self.class.strings_for_charset_id(offset_or_id).size
|
48
100
|
end
|
49
101
|
end
|
50
102
|
|
103
|
+
# Iterate over character names.
|
104
|
+
#
|
105
|
+
# @overload each()
|
106
|
+
# @yieldparam name [String]
|
107
|
+
# @return [void]
|
108
|
+
# @overload each()
|
109
|
+
# @return [Enumerator]
|
51
110
|
def each
|
52
111
|
return to_enum(__method__) unless block_given?
|
53
112
|
|
54
113
|
# +1 adjusts for the implicit .notdef glyph
|
55
|
-
(
|
114
|
+
(items_count + 1).times { |i| yield(self[i]) }
|
56
115
|
end
|
57
116
|
|
117
|
+
# Get character name for glyph index.
|
118
|
+
#
|
119
|
+
# @param glyph_id [Integer]
|
120
|
+
# @return [String, nil]
|
58
121
|
def [](glyph_id)
|
59
122
|
return FIRST_GLYPH_STRING if glyph_id.zero?
|
60
123
|
|
61
124
|
find_string(sid_for(glyph_id))
|
62
125
|
end
|
63
126
|
|
127
|
+
# Charset offset in the file.
|
128
|
+
#
|
129
|
+
# @return [Integer, nil]
|
64
130
|
def offset
|
65
131
|
# Numbers from 0..2 mean charset IDs instead of offsets. IDs are
|
66
132
|
# basically pre-defined sets of characters.
|
@@ -73,13 +139,25 @@ module TTFunk
|
|
73
139
|
end
|
74
140
|
end
|
75
141
|
|
76
|
-
#
|
77
|
-
|
142
|
+
# Encode charset.
|
143
|
+
#
|
144
|
+
# @param charmap [Hash{Integer => Hash}] keys are the charac codes,
|
145
|
+
# values are hashes:
|
146
|
+
# * `:old` (<tt>Integer</tt>) - glyph ID in the original font.
|
147
|
+
# * `:new` (<tt>Integer</tt>) - glyph ID in the subset font.
|
148
|
+
# @return [String]
|
149
|
+
def encode(charmap)
|
78
150
|
# no offset means no charset was specified (i.e. we're supposed to
|
79
151
|
# use a predefined charset) so there's nothing to encode
|
80
152
|
return '' unless offset
|
81
153
|
|
82
|
-
sids =
|
154
|
+
sids =
|
155
|
+
charmap
|
156
|
+
.values
|
157
|
+
.reject { |mapping| mapping[:new].zero? }
|
158
|
+
.sort_by { |mapping| mapping[:new] }
|
159
|
+
.map { |mapping| sid_for(mapping[:old]) }
|
160
|
+
|
83
161
|
ranges = TTFunk::BinUtils.rangify(sids)
|
84
162
|
range_max = ranges.map(&:last).max
|
85
163
|
|
@@ -138,7 +216,7 @@ module TTFunk
|
|
138
216
|
|
139
217
|
idx = sid - 390
|
140
218
|
|
141
|
-
if idx < file.cff.string_index.
|
219
|
+
if idx < file.cff.string_index.items_count
|
142
220
|
file.cff.string_index[idx]
|
143
221
|
end
|
144
222
|
else
|
@@ -153,23 +231,23 @@ module TTFunk
|
|
153
231
|
|
154
232
|
case format_sym
|
155
233
|
when :array_format
|
156
|
-
@
|
157
|
-
@length =
|
234
|
+
@items_count = top_dict.charstrings_index.items_count - 1
|
235
|
+
@length = @items_count * element_width
|
158
236
|
@entries = OneBasedArray.new(read(length, 'n*'))
|
159
237
|
|
160
238
|
when :range_format8, :range_format16
|
161
239
|
# The number of ranges is not explicitly specified in the font.
|
162
240
|
# Instead, software utilizing this data simply processes ranges
|
163
241
|
# until all glyphs in the font are covered.
|
164
|
-
@
|
242
|
+
@items_count = 0
|
165
243
|
@entries = []
|
166
244
|
@length = 0
|
167
245
|
|
168
|
-
until
|
246
|
+
until @items_count >= top_dict.charstrings_index.items_count - 1
|
169
247
|
@length += 1 + element_width
|
170
248
|
sid, num_left = read(element_width, element_format)
|
171
|
-
entries << (sid..(sid + num_left))
|
172
|
-
@
|
249
|
+
@entries << (sid..(sid + num_left))
|
250
|
+
@items_count += num_left + 1
|
173
251
|
end
|
174
252
|
end
|
175
253
|
end
|
@@ -178,7 +256,7 @@ module TTFunk
|
|
178
256
|
{
|
179
257
|
array_format: 2, # SID
|
180
258
|
range_format8: 3, # SID + Card8
|
181
|
-
range_format16: 4 # SID + Card16
|
259
|
+
range_format16: 4, # SID + Card16
|
182
260
|
}[fmt]
|
183
261
|
end
|
184
262
|
|
@@ -186,7 +264,7 @@ module TTFunk
|
|
186
264
|
{
|
187
265
|
array_format: 'n',
|
188
266
|
range_format8: 'nC',
|
189
|
-
range_format16: 'nn'
|
267
|
+
range_format16: 'nn',
|
190
268
|
}[fmt]
|
191
269
|
end
|
192
270
|
|
@@ -204,7 +282,7 @@ module TTFunk
|
|
204
282
|
{
|
205
283
|
array_format: ARRAY_FORMAT,
|
206
284
|
range_format8: RANGE_FORMAT_8,
|
207
|
-
range_format16: RANGE_FORMAT_16
|
285
|
+
range_format16: RANGE_FORMAT_16,
|
208
286
|
}[sym]
|
209
287
|
end
|
210
288
|
end
|
@@ -4,6 +4,7 @@ module TTFunk
|
|
4
4
|
class Table
|
5
5
|
class Cff < TTFunk::Table
|
6
6
|
module Charsets
|
7
|
+
# Predefinde CFF Expert charset
|
7
8
|
EXPERT = OneBasedArray.new(
|
8
9
|
[
|
9
10
|
'space',
|
@@ -180,8 +181,8 @@ module TTFunk
|
|
180
181
|
'Ucircumflexsmall',
|
181
182
|
'Udieresissmall',
|
182
183
|
'Yacutesmall',
|
183
|
-
'Thornsmall'
|
184
|
-
]
|
184
|
+
'Thornsmall',
|
185
|
+
],
|
185
186
|
).freeze
|
186
187
|
end
|
187
188
|
end
|
@@ -4,6 +4,7 @@ module TTFunk
|
|
4
4
|
class Table
|
5
5
|
class Cff < TTFunk::Table
|
6
6
|
module Charsets
|
7
|
+
# Predefined CFF Expert Subset charset
|
7
8
|
EXPERT_SUBSET = OneBasedArray.new(
|
8
9
|
[
|
9
10
|
'space',
|
@@ -110,8 +111,8 @@ module TTFunk
|
|
110
111
|
'nineinferior',
|
111
112
|
'centinferior',
|
112
113
|
'dollarinferior',
|
113
|
-
'periodinferior'
|
114
|
-
]
|
114
|
+
'periodinferior',
|
115
|
+
],
|
115
116
|
).freeze
|
116
117
|
end
|
117
118
|
end
|
@@ -4,6 +4,7 @@ module TTFunk
|
|
4
4
|
class Table
|
5
5
|
class Cff < TTFunk::Table
|
6
6
|
module Charsets
|
7
|
+
# Predefined CFF ISOAdobe charset
|
7
8
|
ISO_ADOBE = OneBasedArray.new(
|
8
9
|
[
|
9
10
|
'space',
|
@@ -232,8 +233,8 @@ module TTFunk
|
|
232
233
|
'ugrave',
|
233
234
|
'yacute',
|
234
235
|
'ydieresis',
|
235
|
-
'zcaron'
|
236
|
-
]
|
236
|
+
'zcaron',
|
237
|
+
],
|
237
238
|
).freeze
|
238
239
|
end
|
239
240
|
end
|
@@ -4,6 +4,7 @@ module TTFunk
|
|
4
4
|
class Table
|
5
5
|
class Cff < TTFunk::Table
|
6
6
|
module Charsets
|
7
|
+
# Standard CFF strings
|
7
8
|
STANDARD_STRINGS = OneBasedArray.new(
|
8
9
|
[
|
9
10
|
'space',
|
@@ -395,8 +396,8 @@ module TTFunk
|
|
395
396
|
'Medium',
|
396
397
|
'Regular',
|
397
398
|
'Roman',
|
398
|
-
'Semibold'
|
399
|
-
]
|
399
|
+
'Semibold',
|
400
|
+
],
|
400
401
|
).freeze
|
401
402
|
end
|
402
403
|
end
|
@@ -3,7 +3,9 @@
|
|
3
3
|
module TTFunk
|
4
4
|
class Table
|
5
5
|
class Cff < TTFunk::Table
|
6
|
+
# CFF Charstring.
|
6
7
|
class Charstring
|
8
|
+
# Type 2 charstring operators
|
7
9
|
CODE_MAP = {
|
8
10
|
1 => :hstem,
|
9
11
|
3 => :vstem,
|
@@ -28,18 +30,29 @@ module TTFunk
|
|
28
30
|
28 => :shortint,
|
29
31
|
29 => :callgsubr,
|
30
32
|
30 => :vhcurveto,
|
31
|
-
31 => :hvcurveto
|
33
|
+
31 => :hvcurveto,
|
32
34
|
}.freeze
|
33
35
|
|
36
|
+
# Type 2 Flex operators.
|
34
37
|
FLEX_CODE_MAP = {
|
35
38
|
35 => :flex,
|
36
39
|
34 => :hflex,
|
37
40
|
36 => :hflex1,
|
38
|
-
37 => :flex1
|
41
|
+
37 => :flex1,
|
39
42
|
}.freeze
|
40
43
|
|
41
|
-
|
44
|
+
# Glyph ID.
|
45
|
+
# @return [Integer]
|
46
|
+
attr_reader :glyph_id
|
42
47
|
|
48
|
+
# Encoded charstring.
|
49
|
+
# @return [String]
|
50
|
+
attr_reader :raw
|
51
|
+
|
52
|
+
# @param glyph_id [Integer]
|
53
|
+
# @param top_dict [TTFunk::Table:Cff::TopDict]
|
54
|
+
# @param font_dict [TTFunk::Table:Cff::FontDict]
|
55
|
+
# @param raw [String]
|
43
56
|
def initialize(glyph_id, top_dict, font_dict, raw)
|
44
57
|
@glyph_id = glyph_id
|
45
58
|
@top_dict = top_dict
|
@@ -66,6 +79,9 @@ module TTFunk
|
|
66
79
|
@y = 0
|
67
80
|
end
|
68
81
|
|
82
|
+
# Get path representation of this charstring.
|
83
|
+
#
|
84
|
+
# @return [TTFunk::Table::Cff::Path]
|
69
85
|
def path
|
70
86
|
@path || begin
|
71
87
|
@path = Path.new
|
@@ -74,6 +90,9 @@ module TTFunk
|
|
74
90
|
end
|
75
91
|
end
|
76
92
|
|
93
|
+
# Get a TrueType-compatible glyph representation of this charstring.
|
94
|
+
#
|
95
|
+
# @return [TTFunk::Table::Glyf::PathBased]
|
77
96
|
def glyph
|
78
97
|
@glyph ||=
|
79
98
|
begin
|
@@ -82,19 +101,21 @@ module TTFunk
|
|
82
101
|
end
|
83
102
|
end
|
84
103
|
|
104
|
+
# Get path representation of this charstring at the specified font size.
|
105
|
+
#
|
106
|
+
# @param x [Integer, Float] new horizontal position.
|
107
|
+
# @param y [Integer, Float] new vertical position.
|
108
|
+
# @param font_size [Integer, Float] font size.
|
109
|
+
# @return [TTFunk::Table::Cff::Path]
|
85
110
|
def render(x: 0, y: 0, font_size: 72)
|
86
111
|
path.render(
|
87
112
|
x: x,
|
88
113
|
y: y,
|
89
114
|
font_size: font_size,
|
90
|
-
units_per_em: @top_dict.file.header.units_per_em
|
115
|
+
units_per_em: @top_dict.file.header.units_per_em,
|
91
116
|
)
|
92
117
|
end
|
93
118
|
|
94
|
-
def encode
|
95
|
-
raw
|
96
|
-
end
|
97
|
-
|
98
119
|
private
|
99
120
|
|
100
121
|
def parse!
|
@@ -106,22 +127,22 @@ module TTFunk
|
|
106
127
|
next if code == 11
|
107
128
|
|
108
129
|
if code >= 32 && code <= 246
|
109
|
-
@stack << code - 139
|
130
|
+
@stack << (code - 139)
|
110
131
|
elsif (m = CODE_MAP[code])
|
111
132
|
__send__(m)
|
112
133
|
elsif code >= 247 && code <= 250
|
113
134
|
b0 = code
|
114
135
|
b1 = @data[@index]
|
115
136
|
@index += 1
|
116
|
-
@stack << (b0 - 247) * 256 + b1 + 108
|
137
|
+
@stack << (((b0 - 247) * 256) + b1 + 108)
|
117
138
|
elsif code >= 251 && code <= 254
|
118
139
|
b0 = code
|
119
140
|
b1 = @data[@index]
|
120
141
|
@index += 1
|
121
|
-
@stack << -(b0 - 251) * 256 - b1 - 108
|
142
|
+
@stack << ((-(b0 - 251) * 256) - b1 - 108)
|
122
143
|
else
|
123
144
|
b1, b2, b3, b4 = read_bytes(4)
|
124
|
-
@stack << ((b1 << 24) | (b2 << 16) | (b3 << 8) | b4) / 65_536
|
145
|
+
@stack << (((b1 << 24) | (b2 << 16) | (b3 << 8) | b4) / 65_536)
|
125
146
|
end
|
126
147
|
end
|
127
148
|
end
|
@@ -3,28 +3,34 @@
|
|
3
3
|
module TTFunk
|
4
4
|
class Table
|
5
5
|
class Cff < TTFunk::Table
|
6
|
+
# CFF Charstrings Index.
|
6
7
|
class CharstringsIndex < TTFunk::Table::Cff::Index
|
8
|
+
# Top dict.
|
9
|
+
# @return [TTFunk::Table::Cff::TopDict]
|
7
10
|
attr_reader :top_dict
|
8
11
|
|
12
|
+
# @overload initialize(top_dict, file, offset, length = nil)
|
13
|
+
# @param top_dict [TTFunk::Table:Cff::TopDict]
|
14
|
+
# @param file [TTFunk::File]
|
15
|
+
# @param offset [Integer]
|
16
|
+
# @param length [Integer]
|
9
17
|
def initialize(top_dict, *remaining_args)
|
10
18
|
super(*remaining_args)
|
11
19
|
@top_dict = top_dict
|
12
20
|
end
|
13
21
|
|
14
|
-
|
15
|
-
entry_cache[index] ||= TTFunk::Table::Cff::Charstring.new(
|
16
|
-
index, top_dict, font_dict_for(index), super
|
17
|
-
)
|
18
|
-
end
|
22
|
+
private
|
19
23
|
|
20
|
-
|
21
|
-
|
22
|
-
super() do |_entry, index|
|
23
|
-
self[mapping[index]].encode if mapping.include?(index)
|
24
|
-
end
|
24
|
+
def decode_item(index, _offset, _length)
|
25
|
+
TTFunk::Table::Cff::Charstring.new(index, top_dict, font_dict_for(index), super)
|
25
26
|
end
|
26
27
|
|
27
|
-
|
28
|
+
def encode_items(charmap)
|
29
|
+
charmap
|
30
|
+
.reject { |code, mapping| mapping[:new].zero? && !code.zero? }
|
31
|
+
.sort_by { |_code, mapping| mapping[:new] }
|
32
|
+
.map { |(_code, mapping)| items[mapping[:old]] }
|
33
|
+
end
|
28
34
|
|
29
35
|
def font_dict_for(index)
|
30
36
|
# only CID-keyed fonts contain an FD selector and font dicts
|