Skip to content

Commit cdb8723

Browse files
committed
Change TrueType subsetter to avoid generating characters that need to be escaped
If text is output into a content stream, it needs to be serialized according to the PDF spec rules. For serializing strings HexaPDF has chosen the literal string syntax because the hexadecimal string syntax would need twice as many characters. For literal strings there are four characters -- \r, (, ), \ -- that need to be escaped. If any of theses characters appears in the string, String#gsub! has to actually do some work modifying the string. By making sure that the encoded text using a TrueType font doesn't contain those characters we avoid this work. This change saves about 31% of object allocations and about 5% runtime on the raw_text 10x TrueType benchmark.
1 parent b461323 commit cdb8723

File tree

1 file changed

+12
-3
lines changed

1 file changed

+12
-3
lines changed

lib/hexapdf/font/true_type/subsetter.rb

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,12 @@ def initialize(font)
6363
def use_glyph(glyph_id)
6464
return @glyph_map[glyph_id] if @glyph_map.key?(glyph_id)
6565
@last_id += 1
66+
# Handle codes for ASCII characters \r, (, ) and \ specially so that they never appear in
67+
# the output (PDF serialization would need to escape them)
68+
if @last_id == 13 || @last_id == 40 || @last_id == 41 || @last_id == 92
69+
@glyph_map[:"s#{@last_id}"] = @last_id
70+
@last_id += 1
71+
end
6672
@glyph_map[glyph_id] = @last_id
6773
end
6874

@@ -107,7 +113,7 @@ def build_glyf_table
107113
locations = []
108114

109115
@glyph_map.each_key do |old_gid|
110-
glyph = orig_glyf[old_gid]
116+
glyph = orig_glyf[old_gid.kind_of?(Symbol) ? 0 : old_gid]
111117
locations << table.size
112118
data = glyph.raw_data
113119
if glyph.compound?
@@ -134,7 +140,7 @@ def build_hmtx_table
134140
hmtx = @font[:hmtx]
135141
data = ''.b
136142
@glyph_map.each_key do |old_gid|
137-
metric = hmtx[old_gid]
143+
metric = hmtx[old_gid.kind_of?(Symbol) ? 0 : old_gid]
138144
data << [metric.advance_width, metric.left_side_bearing].pack('n2')
139145
end
140146
data
@@ -166,7 +172,10 @@ def build_maxp_table(nr_of_glyphs)
166172
# Adds the components of compound glyphs to the subset.
167173
def add_glyph_components
168174
glyf = @font[:glyf]
169-
@glyph_map.keys.each {|gid| glyf[gid].components&.each {|cgid| use_glyph(cgid) } }
175+
@glyph_map.keys.each do |gid|
176+
next if gid.kind_of?(Symbol)
177+
glyf[gid].components&.each {|cgid| use_glyph(cgid) }
178+
end
170179
end
171180

172181
end

0 commit comments

Comments
 (0)