Merge pull request #2275 from fonttools/subset-device
[subset] Fix hint-dropping
This commit is contained in:
commit
9959916c64
@ -14,6 +14,7 @@ import struct
|
|||||||
import array
|
import array
|
||||||
import logging
|
import logging
|
||||||
from collections import Counter, defaultdict
|
from collections import Counter, defaultdict
|
||||||
|
from functools import reduce
|
||||||
from types import MethodType
|
from types import MethodType
|
||||||
|
|
||||||
__usage__ = "pyftsubset font-file [glyph...] [--option=value]..."
|
__usage__ = "pyftsubset font-file [glyph...] [--option=value]..."
|
||||||
@ -527,6 +528,17 @@ def subset_glyphs(self, s):
|
|||||||
else:
|
else:
|
||||||
assert 0, "unknown format: %s" % self.Format
|
assert 0, "unknown format: %s" % self.Format
|
||||||
|
|
||||||
|
@_add_method(otTables.Device)
|
||||||
|
def is_hinting(self):
|
||||||
|
return self.DeltaFormat in (1,2,3)
|
||||||
|
|
||||||
|
@_add_method(otTables.ValueRecord)
|
||||||
|
def prune_hints(self):
|
||||||
|
for name in ['XPlaDevice', 'YPlaDevice', 'XAdvDevice', 'YAdvDevice']:
|
||||||
|
v = getattr(self, name, None)
|
||||||
|
if v is not None and v.is_hinting():
|
||||||
|
delattr(self, name)
|
||||||
|
|
||||||
@_add_method(otTables.SinglePos)
|
@_add_method(otTables.SinglePos)
|
||||||
def subset_glyphs(self, s):
|
def subset_glyphs(self, s):
|
||||||
if self.Format == 1:
|
if self.Format == 1:
|
||||||
@ -543,15 +555,24 @@ def subset_glyphs(self, s):
|
|||||||
|
|
||||||
@_add_method(otTables.SinglePos)
|
@_add_method(otTables.SinglePos)
|
||||||
def prune_post_subset(self, font, options):
|
def prune_post_subset(self, font, options):
|
||||||
if not options.hinting:
|
# Shrink ValueFormat
|
||||||
# Drop device tables
|
if self.Format == 1:
|
||||||
self.ValueFormat &= ~0x00F0
|
if not options.hinting:
|
||||||
|
self.Value.prune_hints()
|
||||||
|
self.ValueFormat = self.Value.getEffectiveFormat()
|
||||||
|
elif self.Format == 2:
|
||||||
|
if not options.hinting:
|
||||||
|
for v in self.Value:
|
||||||
|
v.prune_hints()
|
||||||
|
self.ValueFormat = reduce(int.__or__, [v.getEffectiveFormat() for v in self.Value], 0)
|
||||||
|
|
||||||
# Downgrade to Format 1 if all ValueRecords are the same
|
# Downgrade to Format 1 if all ValueRecords are the same
|
||||||
if self.Format == 2 and all(v == self.Value[0] for v in self.Value):
|
if self.Format == 2 and all(v == self.Value[0] for v in self.Value):
|
||||||
self.Format = 1
|
self.Format = 1
|
||||||
self.Value = self.Value[0] if self.ValueFormat != 0 else None
|
self.Value = self.Value[0] if self.ValueFormat != 0 else None
|
||||||
del self.ValueCount
|
del self.ValueCount
|
||||||
return True
|
|
||||||
|
return bool(self.ValueFormat)
|
||||||
|
|
||||||
@_add_method(otTables.PairPos)
|
@_add_method(otTables.PairPos)
|
||||||
def subset_glyphs(self, s):
|
def subset_glyphs(self, s):
|
||||||
@ -587,10 +608,22 @@ def subset_glyphs(self, s):
|
|||||||
@_add_method(otTables.PairPos)
|
@_add_method(otTables.PairPos)
|
||||||
def prune_post_subset(self, font, options):
|
def prune_post_subset(self, font, options):
|
||||||
if not options.hinting:
|
if not options.hinting:
|
||||||
# Drop device tables
|
attr1, attr2 = {
|
||||||
self.ValueFormat1 &= ~0x00F0
|
1: ('PairSet', 'PairValueRecord'),
|
||||||
self.ValueFormat2 &= ~0x00F0
|
2: ('Class1Record', 'Class2Record'),
|
||||||
return True
|
}[self.Format]
|
||||||
|
|
||||||
|
self.ValueFormat1 = self.ValueFormat2 = 0
|
||||||
|
for row in getattr(self, attr1):
|
||||||
|
for r in getattr(row, attr2):
|
||||||
|
if r.Value1:
|
||||||
|
r.Value1.prune_hints()
|
||||||
|
self.ValueFormat1 |= r.Value1.getEffectiveFormat()
|
||||||
|
if r.Value2:
|
||||||
|
r.Value2.prune_hints()
|
||||||
|
self.ValueFormat2 |= r.Value2.getEffectiveFormat()
|
||||||
|
|
||||||
|
return bool(self.ValueFormat1 | self.ValueFormat2)
|
||||||
|
|
||||||
@_add_method(otTables.CursivePos)
|
@_add_method(otTables.CursivePos)
|
||||||
def subset_glyphs(self, s):
|
def subset_glyphs(self, s):
|
||||||
@ -606,9 +639,15 @@ def subset_glyphs(self, s):
|
|||||||
|
|
||||||
@_add_method(otTables.Anchor)
|
@_add_method(otTables.Anchor)
|
||||||
def prune_hints(self):
|
def prune_hints(self):
|
||||||
# Drop device tables / contour anchor point
|
if self.Format == 2:
|
||||||
self.ensureDecompiled()
|
self.Format = 1
|
||||||
self.Format = 1
|
elif self.Format == 3:
|
||||||
|
for name in ('XDeviceTable', 'YDeviceTable'):
|
||||||
|
v = getattr(self, name, None)
|
||||||
|
if v is not None and v.is_hinting():
|
||||||
|
setattr(self, name, None)
|
||||||
|
if self.XDeviceTable is None and self.YDeviceTable is None:
|
||||||
|
self.Format = 1
|
||||||
|
|
||||||
@_add_method(otTables.CursivePos)
|
@_add_method(otTables.CursivePos)
|
||||||
def prune_post_subset(self, font, options):
|
def prune_post_subset(self, font, options):
|
||||||
@ -713,7 +752,6 @@ def subset_glyphs(self, s):
|
|||||||
@_add_method(otTables.MarkMarkPos)
|
@_add_method(otTables.MarkMarkPos)
|
||||||
def prune_post_subset(self, font, options):
|
def prune_post_subset(self, font, options):
|
||||||
if not options.hinting:
|
if not options.hinting:
|
||||||
# Drop device tables or contour anchor point
|
|
||||||
for m in self.Mark1Array.MarkRecord:
|
for m in self.Mark1Array.MarkRecord:
|
||||||
if m.MarkAnchor:
|
if m.MarkAnchor:
|
||||||
m.MarkAnchor.prune_hints()
|
m.MarkAnchor.prune_hints()
|
||||||
|
@ -970,6 +970,13 @@ class ValueRecord(object):
|
|||||||
format = format | valueRecordFormatDict[name][0]
|
format = format | valueRecordFormatDict[name][0]
|
||||||
return format
|
return format
|
||||||
|
|
||||||
|
def getEffectiveFormat(self):
|
||||||
|
format = 0
|
||||||
|
for name,value in self.__dict__.items():
|
||||||
|
if value:
|
||||||
|
format = format | valueRecordFormatDict[name][0]
|
||||||
|
return format
|
||||||
|
|
||||||
def toXML(self, xmlWriter, font, valueName, attrs=None):
|
def toXML(self, xmlWriter, font, valueName, attrs=None):
|
||||||
if attrs is None:
|
if attrs is None:
|
||||||
simpleItems = []
|
simpleItems = []
|
||||||
|
@ -289,7 +289,7 @@ def merge(merger, self, lst):
|
|||||||
# Merge everything else; though, there shouldn't be anything else. :)
|
# Merge everything else; though, there shouldn't be anything else. :)
|
||||||
merger.mergeObjects(self, lst,
|
merger.mergeObjects(self, lst,
|
||||||
exclude=('Format', 'Coverage', 'Value', 'ValueCount'))
|
exclude=('Format', 'Coverage', 'Value', 'ValueCount'))
|
||||||
self.ValueFormat = reduce(int.__or__, [v.getFormat() for v in self.Value], 0)
|
self.ValueFormat = reduce(int.__or__, [v.getEffectiveFormat() for v in self.Value], 0)
|
||||||
|
|
||||||
@AligningMerger.merger(ot.PairSet)
|
@AligningMerger.merger(ot.PairSet)
|
||||||
def merge(merger, self, lst):
|
def merge(merger, self, lst):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user