Move some methods from subset.py to 'glyf' table implementation

This commit is contained in:
Behdad Esfahbod 2013-09-20 14:10:31 -04:00
parent 46d260f2a0
commit 626107c833
2 changed files with 91 additions and 82 deletions

View File

@ -1118,29 +1118,6 @@ def subset_glyphs(self, s):
self.extraNames = [] # This seems to do it self.extraNames = [] # This seems to do it
return True return True
@_add_method(ttLib.getTableModule('glyf').Glyph)
def getComponentNamesFast(self, glyfTable):
if not self.data or struct.unpack(">h", self.data[:2])[0] >= 0:
return [] # Not composite
data = self.data
i = 10
components = []
more = 1
while more:
flags, glyphID = struct.unpack(">HH", data[i:i+4])
i += 4
flags = int(flags)
components.append(glyfTable.getGlyphName(int(glyphID)))
if flags & 0x0001: i += 4 # ARG_1_AND_2_ARE_WORDS
else: i += 2
if flags & 0x0008: i += 2 # WE_HAVE_A_SCALE
elif flags & 0x0040: i += 4 # WE_HAVE_AN_X_AND_Y_SCALE
elif flags & 0x0080: i += 8 # WE_HAVE_A_TWO_BY_TWO
more = flags & 0x0020 # MORE_COMPONENTS
return components
@_add_method(ttLib.getTableModule('glyf').Glyph) @_add_method(ttLib.getTableModule('glyf').Glyph)
def remapComponentsFast(self, indices): def remapComponentsFast(self, indices):
if not self.data or struct.unpack(">h", self.data[:2])[0] >= 0: if not self.data or struct.unpack(">h", self.data[:2])[0] >= 0:
@ -1167,49 +1144,6 @@ def remapComponentsFast(self, indices):
self.data = data.tostring() self.data = data.tostring()
@_add_method(ttLib.getTableModule('glyf').Glyph)
def dropInstructionsFast(self):
if not self.data:
return
numContours = struct.unpack(">h", self.data[:2])[0]
data = array.array("B", self.data)
i = 10
if numContours >= 0:
i += 2 * numContours # endPtsOfContours
instructionLen =(data[i] << 8) | data[i+1]
# Zero it
data[i] = data [i+1] = 0
i += 2
if instructionLen:
# Splice it out
data = data[:i] + data[i+instructionLen:]
else:
more = 1
while more:
flags =(data[i] << 8) | data[i+1]
# Turn instruction flag off
flags &= ~0x0100 # WE_HAVE_INSTRUCTIONS
data[i+0] = flags >> 8
data[i+1] = flags & 0xFF
i += 4
flags = int(flags)
if flags & 0x0001: i += 4 # ARG_1_AND_2_ARE_WORDS
else: i += 2
if flags & 0x0008: i += 2 # WE_HAVE_A_SCALE
elif flags & 0x0040: i += 4 # WE_HAVE_AN_X_AND_Y_SCALE
elif flags & 0x0080: i += 8 # WE_HAVE_A_TWO_BY_TWO
more = flags & 0x0020 # MORE_COMPONENTS
# Cut off
data = data[:i]
if len(data) % 4:
# add pad bytes
nPadBytes = 4 -(len(data) % 4)
for i in range(nPadBytes):
data.append(0)
self.data = data.tostring()
@_add_method(ttLib.getTableClass('glyf')) @_add_method(ttLib.getTableClass('glyf'))
def closure_glyphs(self, s): def closure_glyphs(self, s):
decompose = s.glyphs decompose = s.glyphs
@ -1221,16 +1155,9 @@ def closure_glyphs(self, s):
if g not in self.glyphs: if g not in self.glyphs:
continue continue
gl = self.glyphs[g] gl = self.glyphs[g]
if hasattr(gl, "data"): for c in gl.getComponents(self):
for c in gl.getComponentNamesFast(self): if c not in s.glyphs:
if c not in s.glyphs: components.add(c)
components.add(c)
else:
# TTX seems to expand gid0..3 always
if gl.isComposite():
for c in gl.components:
if c.glyphName not in s.glyphs:
components.add(c.glyphName)
components = set(c for c in components if c not in s.glyphs) components = set(c for c in components if c not in s.glyphs)
if not components: if not components:
break break
@ -1263,11 +1190,7 @@ def subset_glyphs(self, s):
def prune_post_subset(self, options): def prune_post_subset(self, options):
if not options.hinting: if not options.hinting:
for v in self.glyphs.itervalues(): for v in self.glyphs.itervalues():
if hasattr(v, "data"): v.removeHinting()
v.dropInstructionsFast()
else:
v.program = ttLib.tables.ttProgram.Program()
v.program.fromBytecode([])
return True return True
@_add_method(ttLib.getTableClass('CFF ')) @_add_method(ttLib.getTableClass('CFF '))

View File

@ -549,7 +549,11 @@ class Glyph:
self.xMin, self.yMin, self.xMax, self.yMax = (0, 0, 0, 0) self.xMin, self.yMin, self.xMax, self.yMax = (0, 0, 0, 0)
def isComposite(self): def isComposite(self):
return self.numberOfContours == -1 """Can be called on compact or expanded glyph."""
if hasattr(self, "data"):
return struct.unpack(">h", self.data[:2])[0] == -1
else:
return self.numberOfContours == -1
def __getitem__(self, componentIndex): def __getitem__(self, componentIndex):
if not self.isComposite(): if not self.isComposite():
@ -601,6 +605,88 @@ class Glyph:
else: else:
return GlyphCoordinates(), [], array.array("B") return GlyphCoordinates(), [], array.array("B")
def getComponents(self, glyfTable):
if not hasattr(self, "data"):
if self.isComposite():
return self.components
else:
return []
# Extract components without expanding glyph
if not self.data or struct.unpack(">h", self.data[:2])[0] >= 0:
return [] # Not composite
data = self.data
i = 10
components = []
more = 1
while more:
flags, glyphID = struct.unpack(">HH", data[i:i+4])
i += 4
flags = int(flags)
components.append(glyfTable.getGlyphName(int(glyphID)))
if flags & ARG_1_AND_2_ARE_WORDS: i += 4
else: i += 2
if flags & WE_HAVE_A_SCALE: i += 2
elif flags & WE_HAVE_AN_X_AND_Y_SCALE: i += 4
elif flags & WE_HAVE_A_TWO_BY_TWO: i += 8
more = flags & MORE_COMPONENTS
return components
def removeHinting(self):
if not hasattr(self, "data"):
self.program = ttLib.tables.ttProgram.Program()
self.program.fromBytecode([])
return
# Remove instructions without expanding glyph
if not self.data:
return
numContours = struct.unpack(">h", self.data[:2])[0]
data = array.array("B", self.data)
i = 10
if numContours >= 0:
i += 2 * numContours # endPtsOfContours
instructionLen = (data[i] << 8) | data[i+1]
# Zero it
data[i] = data [i+1] = 0
i += 2
if instructionLen:
# Splice it out
data = data[:i] + data[i+instructionLen:]
else:
more = 1
while more:
flags =(data[i] << 8) | data[i+1]
# Turn instruction flag off
flags &= ~WE_HAVE_INSTRUCTIONS
data[i+0] = flags >> 8
data[i+1] = flags & 0xFF
i += 4
flags = int(flags)
if flags & ARG_1_AND_2_ARE_WORDS: i += 4
else: i += 2
if flags & WE_HAVE_A_SCALE: i += 2
elif flags & WE_HAVE_AN_X_AND_Y_SCALE: i += 4
elif flags & WE_HAVE_A_TWO_BY_TWO: i += 8
more = flags & MORE_COMPONENTS
# Cut off
data = data[:i]
if len(data) % 4:
# add pad bytes
nPadBytes = 4 -(len(data) % 4)
for i in range(nPadBytes):
data.append(0)
self.data = data.tostring()
def __cmp__(self, other): def __cmp__(self, other):
if type(self) != type(other) or \ if type(self) != type(other) or \
self.__class__ != other.__class__: self.__class__ != other.__class__: