Permalink
Browse files

Work around MS fonts with inaccurate kerning table metadata

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.
  • Loading branch information...
1 parent 83139f3 commit 360ff2a54fce81eab9090b6b9fc462ce5210582a @jamis jamis committed Jan 6, 2009
Showing with 36 additions and 10 deletions.
  1. +16 −0 lib/ttfunk/reader.rb
  2. +19 −10 lib/ttfunk/table/kern.rb
  3. +1 −0 lib/ttfunk/table/kern/format0.rb
View
@@ -24,5 +24,21 @@ def parse_from(position)
io.pos = saved
return result
end
+
+ # For debugging purposes
+ def hexdump(string)
+ bytes = string.unpack("C*")
+ bytes.each_with_index do |c, i|
+ print "%02X" % c
+ if (i+1) % 16 == 0
+ puts
+ elsif (i+1) % 8 == 0
+ print " "
+ else
+ print " "
+ end
+ end
+ puts unless bytes.length % 16 == 0
+ end
end
end
View
@@ -30,17 +30,26 @@ def parse!
end
def parse_version_0_tables(num_tables)
- num_tables.times do # MS fonts
- version, length, coverage = read(6, "n*")
- format = coverage >> 8
+ # 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 => io.read(length-6),
- :vertical => (coverage & 0x1 == 0),
- :minimum => (coverage & 0x2 != 0),
- :cross => (coverage & 0x4 != 0),
- :override => (coverage & 0x8 != 0)
- end
+ add_table format, :version => version, :length => length,
+ :coverage => coverage, :data => raw[10..-1],
+ :vertical => (coverage & 0x1 == 0),
+ :minimum => (coverage & 0x2 != 0),
+ :cross => (coverage & 0x4 != 0),
+ :override => (coverage & 0x8 != 0)
end
def parse_version_1_tables(num_tables)
@@ -17,6 +17,7 @@ def initialize(attributes={})
@pairs = {}
num_pairs.times do |i|
+ break if i*3+2 > pairs.length # sanity check, in case there's a bad length somewhere
left = pairs[i*3]
right = pairs[i*3+1]
value = to_signed(pairs[i*3+2])

0 comments on commit 360ff2a

Please sign in to comment.