Merge pull request #1361 from moyogo/kerntable
Ignore the length of kern table sutable format 0
This commit is contained in:
commit
0c4f11f5ff
@ -48,6 +48,19 @@ class table__k_e_r_n(DefaultTable.DefaultTable):
|
|||||||
# This "version" is always 0 so we ignore it here
|
# This "version" is always 0 so we ignore it here
|
||||||
_, length, subtableFormat, coverage = struct.unpack(
|
_, length, subtableFormat, coverage = struct.unpack(
|
||||||
">HHBB", data[:6])
|
">HHBB", data[:6])
|
||||||
|
if nTables == 1 and subtableFormat == 0:
|
||||||
|
# The "length" value is ignored since some fonts
|
||||||
|
# (like OpenSans and Calibri) have a subtable larger than
|
||||||
|
# its value.
|
||||||
|
nPairs, = struct.unpack(">H", data[6:8])
|
||||||
|
calculated_length = (nPairs * 6) + 14
|
||||||
|
if length != calculated_length:
|
||||||
|
log.warning(
|
||||||
|
"'kern' subtable longer than defined: "
|
||||||
|
"%d bytes instead of %d bytes" %
|
||||||
|
(calculated_length, length)
|
||||||
|
)
|
||||||
|
length = calculated_length
|
||||||
if subtableFormat not in kern_classes:
|
if subtableFormat not in kern_classes:
|
||||||
subtable = KernTable_format_unkown(subtableFormat)
|
subtable = KernTable_format_unkown(subtableFormat)
|
||||||
else:
|
else:
|
||||||
@ -128,7 +141,6 @@ class KernTable_format_0(object):
|
|||||||
">HHHH", data[:8])
|
">HHHH", data[:8])
|
||||||
data = data[8:]
|
data = data[8:]
|
||||||
|
|
||||||
nPairs = min(nPairs, len(data) // 6)
|
|
||||||
datas = array.array("H", data[:6 * nPairs])
|
datas = array.array("H", data[:6 * nPairs])
|
||||||
if sys.byteorder != "big": datas.byteswap()
|
if sys.byteorder != "big": datas.byteswap()
|
||||||
it = iter(datas)
|
it = iter(datas)
|
||||||
@ -153,6 +165,7 @@ class KernTable_format_0(object):
|
|||||||
def compile(self, ttFont):
|
def compile(self, ttFont):
|
||||||
nPairs = len(self.kernTable)
|
nPairs = len(self.kernTable)
|
||||||
searchRange, entrySelector, rangeShift = getSearchRange(nPairs, 6)
|
searchRange, entrySelector, rangeShift = getSearchRange(nPairs, 6)
|
||||||
|
searchRange &= 0xFFFF
|
||||||
data = struct.pack(
|
data = struct.pack(
|
||||||
">HHHH", nPairs, searchRange, entrySelector, rangeShift)
|
">HHHH", nPairs, searchRange, entrySelector, rangeShift)
|
||||||
|
|
||||||
@ -175,6 +188,10 @@ class KernTable_format_0(object):
|
|||||||
if not self.apple:
|
if not self.apple:
|
||||||
version = 0
|
version = 0
|
||||||
length = len(data) + 6
|
length = len(data) + 6
|
||||||
|
if length >= 0x10000:
|
||||||
|
log.warning('"kern" subtable overflow, '
|
||||||
|
'truncating length value while preserving pairs.')
|
||||||
|
length &= 0xFFFF
|
||||||
header = struct.pack(
|
header = struct.pack(
|
||||||
">HHBB", version, length, self.format, self.coverage)
|
">HHBB", version, length, self.format, self.coverage)
|
||||||
else:
|
else:
|
||||||
|
@ -5,6 +5,7 @@ from fontTools.ttLib.tables._k_e_r_n import (
|
|||||||
KernTable_format_0, KernTable_format_unkown)
|
KernTable_format_0, KernTable_format_unkown)
|
||||||
from fontTools.misc.textTools import deHexStr
|
from fontTools.misc.textTools import deHexStr
|
||||||
from fontTools.misc.testTools import FakeFont, getXML, parseXML
|
from fontTools.misc.testTools import FakeFont, getXML, parseXML
|
||||||
|
import itertools
|
||||||
import pytest
|
import pytest
|
||||||
|
|
||||||
|
|
||||||
@ -120,12 +121,32 @@ KERN_VER_1_FMT_UNKNOWN_XML = [
|
|||||||
'</kernsubtable>',
|
'</kernsubtable>',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
KERN_VER_0_FMT_0_OVERFLOWING_DATA = deHexStr(
|
||||||
|
'0000 ' # 0: version=0
|
||||||
|
'0001 ' # 2: nTables=1
|
||||||
|
'0000 ' # 4: version=0 (bogus field, unused)
|
||||||
|
'0274 ' # 6: length=628 (bogus value for 66164 % 0x10000)
|
||||||
|
'00 ' # 8: format=0
|
||||||
|
'01 ' # 9: coverage=1
|
||||||
|
'2B11 ' # 10: nPairs=11025
|
||||||
|
'C000 ' # 12: searchRange=49152
|
||||||
|
'000D ' # 14: entrySelector=13
|
||||||
|
'4266 ' # 16: rangeShift=16998
|
||||||
|
) + deHexStr(' '.join(
|
||||||
|
'%04X %04X %04X' % (a, b, 0)
|
||||||
|
for (a, b) in itertools.product(range(105), repeat=2)
|
||||||
|
))
|
||||||
|
|
||||||
|
|
||||||
@pytest.fixture
|
@pytest.fixture
|
||||||
def font():
|
def font():
|
||||||
return FakeFont(list("ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
return FakeFont(list("ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||||
"abcdefghijklmnopqrstuvwxyz"))
|
"abcdefghijklmnopqrstuvwxyz"))
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def overflowing_font():
|
||||||
|
return FakeFont(["glyph%i" % i for i in range(105)])
|
||||||
|
|
||||||
|
|
||||||
class KernTableTest(object):
|
class KernTableTest(object):
|
||||||
|
|
||||||
@ -364,6 +385,36 @@ class KernTable_format_0_Test(object):
|
|||||||
assert subtable[("B", "D")] == 1
|
assert subtable[("B", "D")] == 1
|
||||||
assert subtable[("B", "glyph65535")] == 2
|
assert subtable[("B", "glyph65535")] == 2
|
||||||
|
|
||||||
|
def test_compileOverflowingSubtable(self, overflowing_font):
|
||||||
|
font = overflowing_font
|
||||||
|
kern = newTable("kern")
|
||||||
|
kern.version = 0
|
||||||
|
st = KernTable_format_0(0)
|
||||||
|
kern.kernTables = [st]
|
||||||
|
st.coverage = 1
|
||||||
|
st.tupleIndex = None
|
||||||
|
st.kernTable = {
|
||||||
|
(a, b): 0
|
||||||
|
for (a, b) in itertools.product(
|
||||||
|
font.getGlyphOrder(), repeat=2)
|
||||||
|
}
|
||||||
|
assert len(st.kernTable) == 11025
|
||||||
|
data = kern.compile(font)
|
||||||
|
assert data == KERN_VER_0_FMT_0_OVERFLOWING_DATA
|
||||||
|
|
||||||
|
def test_decompileOverflowingSubtable(self, overflowing_font):
|
||||||
|
font = overflowing_font
|
||||||
|
data = KERN_VER_0_FMT_0_OVERFLOWING_DATA
|
||||||
|
kern = newTable("kern")
|
||||||
|
kern.decompile(data, font)
|
||||||
|
|
||||||
|
st = kern.kernTables[0]
|
||||||
|
assert st.kernTable == {
|
||||||
|
(a, b): 0
|
||||||
|
for (a, b) in itertools.product(
|
||||||
|
font.getGlyphOrder(), repeat=2)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
import sys
|
import sys
|
||||||
|
Loading…
x
Reference in New Issue
Block a user