1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
|
# frozen_string_literal: true
require_relative '../../reader'
module TTFunk
class Table
class Kern
# Format 0 kerning subtable.
class Format0
include Reader
# Subtable attributes.
# @return [Hash{Symbol => any}]
attr_reader :attributes
# Kerning pairs.
# @return [Hash{Array(Integer, Integer) => Integer}]
attr_reader :pairs
# @param attributes [Hash{Symbol => any}]
def initialize(attributes = {})
@attributes = attributes
num_pairs, *pairs = attributes.delete(:data).unpack('nx6n*')
@pairs = {}
num_pairs.times do |i|
# sanity check, in case there's a bad length somewhere
break if (i * 3) + 2 > pairs.length
left = pairs[i * 3]
right = pairs[(i * 3) + 1]
value = to_signed(pairs[(i * 3) + 2])
@pairs[[left, right]] = value
end
end
# Is this vertical kerning?
# @return [Boolean]
def vertical?
@attributes[:vertical]
end
# Is this horizontal kerning?
# @return [Boolean]
def horizontal?
!vertical?
end
# Is this cross-stream kerning?
# @return [Boolean]
def cross_stream?
@attributes[:cross]
end
# Recode this subtable using the specified mapping.
#
# @param mapping [Hash{Integer => Integer}] keys are new glyph IDs,
# values are old glyph IDs
# @return [String]
def recode(mapping)
subset = []
pairs.each do |(left, right), value|
if mapping[left] && mapping[right]
subset << [mapping[left], mapping[right], value]
end
end
return if subset.empty?
num_pairs = subset.length
search_range = 2 * (2**Integer(Math.log(num_pairs) / Math.log(2)))
entry_selector = Integer(Math.log(search_range / 2) / Math.log(2))
range_shift = (2 * num_pairs) - search_range
[
attributes[:version],
(num_pairs * 6) + 14,
attributes[:coverage],
num_pairs,
search_range,
entry_selector,
range_shift,
subset,
].flatten.pack('n*')
end
end
end
end
end
|