[woff2] Add support for encoding/decoding OVERLAP_SIMPLE glyf flags in WOFF2
Fixes #2576 This updates our woff2 encoder/decoder to support retaining the OVERLAP_SIMPLE glyf flag following the updated WOFF 2.0 specification and official google/woff2 implementation. https://www.w3.org/TR/WOFF2/#glyf_table_format
This commit is contained in:
parent
12bf60aee0
commit
b4e664da21
@ -523,7 +523,8 @@ woff2TransformedTableTags = ('glyf', 'loca')
|
||||
|
||||
woff2GlyfTableFormat = """
|
||||
> # big endian
|
||||
version: L # = 0x00000000
|
||||
version: H # = 0x0000
|
||||
optionFlags: H # Bit 0: we have overlapSimpleBitmap[], Bits 1-15: reserved
|
||||
numGlyphs: H # Number of glyphs
|
||||
indexFormat: H # Offset format for loca table
|
||||
nContourStreamSize: L # Size of nContour stream
|
||||
@ -545,6 +546,8 @@ bboxFormat = """
|
||||
yMax: h
|
||||
"""
|
||||
|
||||
woff2OverlapSimpleBitmapFlag = 0x0001
|
||||
|
||||
|
||||
def getKnownTagIndex(tag):
|
||||
"""Return index of 'tag' in woff2KnownTags list. Return 63 if not found."""
|
||||
@ -690,6 +693,13 @@ class WOFF2GlyfTable(getTableClass('glyf')):
|
||||
data = data[size:]
|
||||
offset += size
|
||||
|
||||
hasOverlapSimpleBitmap = self.optionFlags & woff2OverlapSimpleBitmapFlag
|
||||
self.overlapSimpleBitmap = None
|
||||
if hasOverlapSimpleBitmap:
|
||||
overlapSimpleBitmapSize = (self.numGlyphs + 7) >> 3
|
||||
self.overlapSimpleBitmap = array.array('B', data[:overlapSimpleBitmapSize])
|
||||
offset += overlapSimpleBitmapSize
|
||||
|
||||
if offset != inputDataSize:
|
||||
raise TTLibError(
|
||||
"incorrect size of transformed 'glyf' table: expected %d, received %d bytes"
|
||||
@ -737,15 +747,22 @@ class WOFF2GlyfTable(getTableClass('glyf')):
|
||||
bboxBitmapSize = ((self.numGlyphs + 31) >> 5) << 2
|
||||
self.bboxBitmap = array.array('B', [0]*bboxBitmapSize)
|
||||
|
||||
self.overlapSimpleBitmap = array.array('B', [0]*((self.numGlyphs + 7) >> 3))
|
||||
for glyphID in range(self.numGlyphs):
|
||||
self._encodeGlyph(glyphID)
|
||||
hasOverlapSimpleBitmap = any(self.overlapSimpleBitmap)
|
||||
|
||||
self.bboxStream = self.bboxBitmap.tobytes() + self.bboxStream
|
||||
for stream in self.subStreams:
|
||||
setattr(self, stream + 'Size', len(getattr(self, stream)))
|
||||
self.version = 0
|
||||
self.optionFlags = 0
|
||||
if hasOverlapSimpleBitmap:
|
||||
self.optionFlags |= woff2OverlapSimpleBitmapFlag
|
||||
data = sstruct.pack(woff2GlyfTableFormat, self)
|
||||
data += bytesjoin([getattr(self, s) for s in self.subStreams])
|
||||
if hasOverlapSimpleBitmap:
|
||||
data += self.overlapSimpleBitmap.tobytes()
|
||||
return data
|
||||
|
||||
def _decodeGlyph(self, glyphID):
|
||||
@ -757,6 +774,7 @@ class WOFF2GlyfTable(getTableClass('glyf')):
|
||||
self._decodeComponents(glyph)
|
||||
else:
|
||||
self._decodeCoordinates(glyph)
|
||||
self._decodeOverlapSimpleFlag(glyph, glyphID)
|
||||
self._decodeBBox(glyphID, glyph)
|
||||
return glyph
|
||||
|
||||
@ -787,6 +805,14 @@ class WOFF2GlyfTable(getTableClass('glyf')):
|
||||
self._decodeTriplets(glyph)
|
||||
self._decodeInstructions(glyph)
|
||||
|
||||
def _decodeOverlapSimpleFlag(self, glyph, glyphID):
|
||||
if self.overlapSimpleBitmap is None or glyph.numberOfContours <= 0:
|
||||
return
|
||||
byte = glyphID >> 3
|
||||
bit = glyphID & 7
|
||||
if self.overlapSimpleBitmap[byte] & (0x80 >> bit):
|
||||
glyph.flags[0] |= _g_l_y_f.flagOverlapSimple
|
||||
|
||||
def _decodeInstructions(self, glyph):
|
||||
glyphStream = self.glyphStream
|
||||
instructionStream = self.instructionStream
|
||||
@ -885,6 +911,7 @@ class WOFF2GlyfTable(getTableClass('glyf')):
|
||||
self._encodeComponents(glyph)
|
||||
else:
|
||||
self._encodeCoordinates(glyph)
|
||||
self._encodeOverlapSimpleFlag(glyph, glyphID)
|
||||
self._encodeBBox(glyphID, glyph)
|
||||
|
||||
def _encodeComponents(self, glyph):
|
||||
@ -909,6 +936,14 @@ class WOFF2GlyfTable(getTableClass('glyf')):
|
||||
self._encodeTriplets(glyph)
|
||||
self._encodeInstructions(glyph)
|
||||
|
||||
def _encodeOverlapSimpleFlag(self, glyph, glyphID):
|
||||
if glyph.numberOfContours <= 0:
|
||||
return
|
||||
if glyph.flags[0] & _g_l_y_f.flagOverlapSimple:
|
||||
byte = glyphID >> 3
|
||||
bit = glyphID & 7
|
||||
self.overlapSimpleBitmap[byte] |= 0x80 >> bit
|
||||
|
||||
def _encodeInstructions(self, glyph):
|
||||
instructions = glyph.program.getBytecode()
|
||||
self.glyphStream += pack255UShort(len(instructions))
|
||||
|
@ -1239,7 +1239,10 @@ class WOFF2RoundtripTest(object):
|
||||
|
||||
_, ttFont2 = self.roundtrip(tmp)
|
||||
assert ttFont2.flavor == "woff2"
|
||||
assert ttFont2["glyf"]["A"].flags[0] == 0
|
||||
# check that the off-curve point is still there
|
||||
assert ttFont2["glyf"]["A"].flags[0] & _g_l_y_f.flagOnCurve == 0
|
||||
# check that the overlap bit is still there
|
||||
assert ttFont2["glyf"]["A"].flags[0] & _g_l_y_f.flagOverlapSimple != 0
|
||||
|
||||
class MainTest(object):
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user