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 91 92 93 94 95 96 97 98 99 100 101 102 103
|
# frozen_string_literal: true
require_relative '../table'
module TTFunk
class Table
# Kerning (`kern`) table
class Kern < Table
# Table version
# @return [Integer]
attr_reader :version
# Subtables.
# @return [Array<TTFunk::Table::Kern::Format0>]
attr_reader :tables
# Encode table.
#
# @param kerning [TTFunk::Table::Kern]
# @param mapping [Hash{Integer => Integer}] keys are new glyph IDs, values
# are old glyph IDs
# @return [String, nil]
def self.encode(kerning, mapping)
return unless kerning.exists? && kerning.tables.any?
tables = kerning.tables.filter_map { |table| table.recode(mapping) }
return if tables.empty?
[0, tables.length, tables.join].pack('nnA*')
end
private
def parse!
@version, num_tables = read(4, 'n*')
@tables = []
if @version == 1 # Mac OS X fonts
@version = (@version << 16) + num_tables
num_tables = read(4, 'N').first
parse_version_1_tables(num_tables)
else
parse_version_0_tables(num_tables)
end
end
def parse_version_0_tables(_num_tables)
# It looks like some MS fonts report their kerning subtable lengths
# wrong. In one case, the length was reported to be some 19366, and yet
# the table also claimed to hold 14148 pairs (each pair consisting of
# 6 bytes). You do the math!
#
# We're going to assume that the microsoft fonts hold only a single
# kerning subtable, which occupies the entire length of the kerning
# table. Worst case, we lose any other subtables that the font contains,
# but it's better than reading a truncated kerning table.
#
# And what's more, it appears to work. So.
version, length, coverage = read(6, 'n*')
format = coverage >> 8
add_table(
format,
version: version,
length: length,
coverage: coverage,
data: raw[10..],
vertical: (coverage & 0x1).zero?,
minimum: (coverage & 0x2 != 0),
cross: (coverage & 0x4 != 0),
override: (coverage & 0x8 != 0),
)
end
def parse_version_1_tables(num_tables)
num_tables.times do
length, coverage, tuple_index = read(8, 'Nnn')
format = coverage & 0x0FF
add_table(
format,
length: length,
coverage: coverage,
tuple_index: tuple_index,
data: io.read(length - 8),
vertical: (coverage & 0x8000 != 0),
cross: (coverage & 0x4000 != 0),
variation: (coverage & 0x2000 != 0),
)
end
end
def add_table(format, attributes = {})
if format.zero?
@tables << Kern::Format0.new(attributes)
end
# Unsupported kerning tables are silently ignored
end
end
end
end
require_relative 'kern/format0'
|