Merge pull request #1443 from fonttools/subset-retain-gids

[subset] Add --retain-gids to retain glyph indices
This commit is contained in:
Cosimo Lupo 2019-01-15 11:30:38 +00:00 committed by GitHub
commit c7b66dc59c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -123,6 +123,8 @@ Output options:
Glyph set expansion: Glyph set expansion:
These options control how additional glyphs are added to the subset. These options control how additional glyphs are added to the subset.
--retain-gids
Retain glyph indices; just empty glyphs not needed in-place.
--notdef-glyph --notdef-glyph
Add the '.notdef' glyph to the subset (ie, keep it). [default] Add the '.notdef' glyph to the subset (ie, keep it). [default]
--no-notdef-glyph --no-notdef-glyph
@ -1714,11 +1716,15 @@ def subset_glyphs(self, s):
@_add_method(ttLib.getTableClass('vmtx')) @_add_method(ttLib.getTableClass('vmtx'))
def subset_glyphs(self, s): def subset_glyphs(self, s):
self.metrics = _dict_subset(self.metrics, s.glyphs) self.metrics = _dict_subset(self.metrics, s.glyphs)
for g in s.glyphs_emptied:
self.metrics[g] = (0,0)
return bool(self.metrics) return bool(self.metrics)
@_add_method(ttLib.getTableClass('hmtx')) @_add_method(ttLib.getTableClass('hmtx'))
def subset_glyphs(self, s): def subset_glyphs(self, s):
self.metrics = _dict_subset(self.metrics, s.glyphs) self.metrics = _dict_subset(self.metrics, s.glyphs)
for g in s.glyphs_emptied:
self.metrics[g] = (0,0)
return True # Required table return True # Required table
@_add_method(ttLib.getTableClass('hdmx')) @_add_method(ttLib.getTableClass('hdmx'))
@ -1784,6 +1790,8 @@ def subset_glyphs(self, s):
def subset_glyphs(self, s): def subset_glyphs(self, s):
table = self.table table = self.table
# TODO Update for retain_gids
used = set() used = set()
if table.AdvWidthMap: if table.AdvWidthMap:
@ -2010,7 +2018,7 @@ def subset_glyphs(self, s):
return True return True
@_add_method(ttLib.getTableModule('glyf').Glyph) @_add_method(ttLib.getTableModule('glyf').Glyph)
def remapComponentsFast(self, indices): def remapComponentsFast(self, glyphidmap):
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:
return # Not composite return # Not composite
data = array.array("B", self.data) data = array.array("B", self.data)
@ -2020,7 +2028,7 @@ def remapComponentsFast(self, indices):
flags =(data[i] << 8) | data[i+1] flags =(data[i] << 8) | data[i+1]
glyphID =(data[i+2] << 8) | data[i+3] glyphID =(data[i+2] << 8) | data[i+3]
# Remap # Remap
glyphID = indices.index(glyphID) glyphID = glyphidmap[glyphID]
data[i+2] = glyphID >> 8 data[i+2] = glyphID >> 8
data[i+3] = glyphID & 0xFF data[i+3] = glyphID & 0xFF
i += 4 i += 4
@ -2063,13 +2071,17 @@ def prune_pre_subset(self, font, options):
@_add_method(ttLib.getTableClass('glyf')) @_add_method(ttLib.getTableClass('glyf'))
def subset_glyphs(self, s): def subset_glyphs(self, s):
self.glyphs = _dict_subset(self.glyphs, s.glyphs) self.glyphs = _dict_subset(self.glyphs, s.glyphs)
if not s.options.retain_gids:
indices = [i for i,g in enumerate(self.glyphOrder) if g in s.glyphs] indices = [i for i,g in enumerate(self.glyphOrder) if g in s.glyphs]
glyphmap = {o:n for n,o in enumerate(indices)}
for v in self.glyphs.values(): for v in self.glyphs.values():
if hasattr(v, "data"): if hasattr(v, "data"):
v.remapComponentsFast(indices) v.remapComponentsFast(glyphmap)
else: Glyph = ttLib.getTableModule('glyf').Glyph
pass # No need for g in s.glyphs_emptied:
self.glyphOrder = [g for g in self.glyphOrder if g in s.glyphs] self.glyphs[g] = Glyph()
self.glyphs[g].data = ''
self.glyphOrder = [g for g in self.glyphOrder if g in s.glyphs or g in s.glyphs_emptied]
# Don't drop empty 'glyf' tables, otherwise 'loca' doesn't get subset. # Don't drop empty 'glyf' tables, otherwise 'loca' doesn't get subset.
return True return True
@ -2275,6 +2287,7 @@ class Options(object):
self.name_legacy = False self.name_legacy = False
self.name_languages = [0x0409] # English self.name_languages = [0x0409] # English
self.obfuscate_names = False # to make webfont unusable as a system font self.obfuscate_names = False # to make webfont unusable as a system font
self.retain_gids = False
self.notdef_glyph = True # gid0 for TrueType / .notdef for CFF self.notdef_glyph = True # gid0 for TrueType / .notdef for CFF
self.notdef_outline = False # No need for notdef to have an outline really self.notdef_outline = False # No need for notdef to have an outline really
self.recommended_glyphs = False # gid1, gid2, gid3 for TrueType self.recommended_glyphs = False # gid1, gid2, gid3 for TrueType
@ -2533,12 +2546,17 @@ class Subsetter(object):
log.glyphs(self.glyphs, font=font) log.glyphs(self.glyphs, font=font)
self.glyphs_cffed = frozenset(self.glyphs) self.glyphs_cffed = frozenset(self.glyphs)
self.glyphs_all = frozenset(self.glyphs) self.glyphs_retained = frozenset(self.glyphs)
self.glyphs_emptied = frozenset()
if self.options.retain_gids:
self.glyphs_emptied = realGlyphs - self.glyphs_retained
# TODO Drop empty glyphs at the end of GlyphOrder vector.
order = font.getReverseGlyphMap() order = font.getReverseGlyphMap()
self.reverseOrigGlyphMap = {g:order[g] for g in self.glyphs_all} self.reverseOrigGlyphMap = {g:order[g] for g in self.glyphs_retained}
log.info("Retaining %d glyphs", len(self.glyphs_all)) log.info("Retaining %d glyphs", len(self.glyphs_retained))
del self.glyphs del self.glyphs
@ -2551,7 +2569,7 @@ class Subsetter(object):
elif hasattr(clazz, 'subset_glyphs'): elif hasattr(clazz, 'subset_glyphs'):
with timer("subset '%s'" % tag): with timer("subset '%s'" % tag):
table = font[tag] table = font[tag]
self.glyphs = self.glyphs_all self.glyphs = self.glyphs_retained
retain = table.subset_glyphs(self) retain = table.subset_glyphs(self)
del self.glyphs del self.glyphs
if not retain: if not retain:
@ -2565,9 +2583,10 @@ class Subsetter(object):
log.warning("%s NOT subset; don't know how to subset; dropped", tag) log.warning("%s NOT subset; don't know how to subset; dropped", tag)
del font[tag] del font[tag]
if not self.options.retain_gids:
with timer("subset GlyphOrder"): with timer("subset GlyphOrder"):
glyphOrder = font.getGlyphOrder() glyphOrder = font.getGlyphOrder()
glyphOrder = [g for g in glyphOrder if g in self.glyphs_all] glyphOrder = [g for g in glyphOrder if g in self.glyphs_retained]
font.setGlyphOrder(glyphOrder) font.setGlyphOrder(glyphOrder)
font._buildReverseGlyphOrderDict() font._buildReverseGlyphOrderDict()