Improve subsetting of Context formats
When recursing for closure, just pass down glyphs that could have actually matched the rule. This can result in wrong results if the recursed lookup is NOT one-to-one. Fix coming. In the mean time, test with NotoSansDevanagari-Bold.ttf and chars uni91f,uni94d,uni930 to see the difference.
This commit is contained in:
parent
6c11b894f3
commit
849d25c95d
100
pyotlss.py
100
pyotlss.py
@ -49,6 +49,11 @@ def intersect (self, glyphs):
|
||||
"Returns ascending list of matching coverage values."
|
||||
return [i for (i,g) in enumerate (self.glyphs) if g in glyphs]
|
||||
|
||||
@add_method(fontTools.ttLib.tables.otTables.Coverage)
|
||||
def intersect_glyphs (self, glyphs):
|
||||
"Returns set of intersecting glyphs."
|
||||
return set (g for g in self.glyphs if g in glyphs)
|
||||
|
||||
@add_method(fontTools.ttLib.tables.otTables.Coverage)
|
||||
def subset (self, glyphs):
|
||||
"Returns ascending list of remaining coverage values."
|
||||
@ -68,14 +73,11 @@ def intersect (self, glyphs):
|
||||
[v for g,v in self.classDefs.items() if g in glyphs])
|
||||
|
||||
@add_method(fontTools.ttLib.tables.otTables.ClassDef)
|
||||
def intersects_class (self, glyphs, klass):
|
||||
"Returns true if any of glyphs has requested class."
|
||||
assert isinstance (klass, int)
|
||||
def intersect_class (self, glyphs, klass):
|
||||
"Returns set of glyphs matching class."
|
||||
if klass == 0:
|
||||
if any (g not in self.classDefs for g in glyphs):
|
||||
return True
|
||||
# Fall through
|
||||
return any (g in glyphs for g,v in self.classDefs.items() if v == klass)
|
||||
return set (g for g in glyphs if g not in self.classDefs)
|
||||
return set (g for g,v in self.classDefs.items() if v == klass and g in glyphs)
|
||||
|
||||
@add_method(fontTools.ttLib.tables.otTables.ClassDef)
|
||||
def subset (self, glyphs, remap=False):
|
||||
@ -362,10 +364,10 @@ def __classify_context (self):
|
||||
if Format == 1:
|
||||
Coverage = lambda r: r.Coverage
|
||||
ChainCoverage = lambda r: r.Coverage
|
||||
ContextData = None
|
||||
ChainContextData = None
|
||||
RuleData = lambda r: r.Input
|
||||
ChainRuleData = lambda r: r.Backtrack + r.Input + r.LookAhead
|
||||
ContextData = lambda r: (None,)
|
||||
ChainContextData = lambda r: (None, None, None)
|
||||
RuleData = lambda r: (r.Input,)
|
||||
ChainRuleData = lambda r: (r.Backtrack, r.Input, r.LookAhead)
|
||||
SetRuleData = None
|
||||
ChainSetRuleData = None
|
||||
elif Format == 2:
|
||||
@ -405,11 +407,13 @@ def __classify_context (self):
|
||||
self.RuleCount = ChainTyp+'RuleCount'
|
||||
self.RuleSet = ChainTyp+'RuleSet'
|
||||
self.RuleSetCount = ChainTyp+'RuleSetCount'
|
||||
self.Intersect = lambda glyphs, ContextData, RuleData: [RuleData] if RuleData in glyphs else []
|
||||
elif Format == 2:
|
||||
self.Rule = ChainTyp+'ClassRule'
|
||||
self.RuleCount = ChainTyp+'ClassRuleCount'
|
||||
self.RuleSet = ChainTyp+'ClassSet'
|
||||
self.RuleSetCount = ChainTyp+'ClassSetCount'
|
||||
self.Intersect = lambda glyphs, ContextData, RuleData: ContextData.intersect_class (glyphs, RuleData)
|
||||
|
||||
self.ClassDef = 'InputClassDef' if Chain else 'ClassDef'
|
||||
|
||||
@ -429,34 +433,65 @@ def closure_glyphs (self, s, cur_glyphs=None):
|
||||
indices = c.Coverage (self).intersect (s.glyphs)
|
||||
if not indices:
|
||||
return []
|
||||
cur_glyphs = set (g for g in c.Coverage (self).glyphs if g in s.glyphs)
|
||||
cur_glyphs = c.Coverage (self).intersect_glyphs (s.glyphs);
|
||||
|
||||
if self.Format == 1:
|
||||
ContextData = c.ContextData (self)
|
||||
rss = getattr (self, c.RuleSet)
|
||||
return sum ((s.table.LookupList.Lookup[ll.LookupListIndex].closure_glyphs \
|
||||
(s, cur_glyphs=(cur_glyphs if ll.SequenceIndex == 0 else s.glyphs)) \
|
||||
for i in indices if rss[i] \
|
||||
for r in getattr (rss[i], c.Rule) \
|
||||
if r and all (g in s.glyphs for g in c.RuleData (r)) \
|
||||
for ll in getattr (r, c.LookupRecord) if ll \
|
||||
), [])
|
||||
add = []
|
||||
for i in indices:
|
||||
if not rss[i]: continue
|
||||
for r in getattr (rss[i], c.Rule):
|
||||
if not r: continue
|
||||
if all (all (c.Intersect (s.glyphs, cd, k) for k in klist)
|
||||
for cd,klist in zip (ContextData, c.RuleData (r))):
|
||||
for ll in getattr (r, c.LookupRecord):
|
||||
if not ll: continue
|
||||
seqi = ll.SequenceIndex
|
||||
if seqi == 0:
|
||||
pos_glyphs = set (c.Coverage (self).glyphs[i])
|
||||
else:
|
||||
pos_glyphs = set (r.Input[seqi - 1])
|
||||
lookup = s.table.LookupList.Lookup[ll.LookupListIndex]
|
||||
add.extend (lookup.closure_glyphs (s, cur_glyphs=pos_glyphs))
|
||||
return add
|
||||
elif self.Format == 2:
|
||||
indices = getattr (self, c.ClassDef).intersect (cur_glyphs)
|
||||
ClassDef = getattr (self, c.ClassDef)
|
||||
indices = ClassDef.intersect (cur_glyphs)
|
||||
ContextData = c.ContextData (self)
|
||||
rss = getattr (self, c.RuleSet)
|
||||
return sum ((s.table.LookupList.Lookup[ll.LookupListIndex].closure_glyphs \
|
||||
(s, cur_glyphs=(cur_glyphs if ll.SequenceIndex == 0 else s.glyphs)) \
|
||||
for i in indices if rss[i] \
|
||||
for r in getattr (rss[i], c.Rule) \
|
||||
if r and all (all (cd.intersects_class (s.glyphs, k) for k in klist) \
|
||||
for cd,klist in zip (c.ContextData (self), c.RuleData (r))) \
|
||||
for ll in getattr (r, c.LookupRecord) if ll \
|
||||
), [])
|
||||
add = []
|
||||
for i in indices:
|
||||
if not rss[i]: continue
|
||||
for r in getattr (rss[i], c.Rule):
|
||||
if not r: continue
|
||||
if all (all (c.Intersect (s.glyphs, cd, k) for k in klist)
|
||||
for cd,klist in zip (ContextData, c.RuleData (r))):
|
||||
for ll in getattr (r, c.LookupRecord):
|
||||
if not ll: continue
|
||||
seqi = ll.SequenceIndex
|
||||
if seqi == 0:
|
||||
pos_glyphs = ClassDef.intersect_class (cur_glyphs, i)
|
||||
else:
|
||||
pos_glyphs = ClassDef.intersect_class (s.glyphs, r.Input[seqi - 1])
|
||||
lookup = s.table.LookupList.Lookup[ll.LookupListIndex]
|
||||
add.extend (lookup.closure_glyphs (s, cur_glyphs=pos_glyphs))
|
||||
return add
|
||||
elif self.Format == 3:
|
||||
if not all (x.intersect (s.glyphs) for x in c.RuleData (self)):
|
||||
return []
|
||||
return sum ((s.table.LookupList.Lookup[ll.LookupListIndex].closure_glyphs \
|
||||
(s, cur_glyphs=(cur_glyphs if ll.SequenceIndex == 0 else s.glyphs)) \
|
||||
for ll in getattr (self, c.LookupRecord) if ll), [])
|
||||
r = self
|
||||
add = []
|
||||
for ll in getattr (r, c.LookupRecord):
|
||||
if not ll: continue
|
||||
seqi = ll.SequenceIndex
|
||||
if seqi == 0:
|
||||
pos_glyphs = cur_glyphs
|
||||
else:
|
||||
pos_glyphs = r.InputCoverage[seqi].intersect_glyphs (s.glyphs)
|
||||
lookup = s.table.LookupList.Lookup[ll.LookupListIndex]
|
||||
add.extend (lookup.closure_glyphs (s, cur_glyphs=pos_glyphs))
|
||||
return add
|
||||
else:
|
||||
assert 0, "unknown format: %s" % self.Format
|
||||
|
||||
@ -473,7 +508,8 @@ def subset_glyphs (self, s):
|
||||
if not rs: continue
|
||||
ss = getattr (rs, c.Rule)
|
||||
ss = [r for r in ss \
|
||||
if r and all (g in s.glyphs for g in c.RuleData (r))]
|
||||
if r and all (all (g in s.glyphs for g in glist) \
|
||||
for glist in c.RuleData (r))]
|
||||
setattr (rs, c.Rule, ss)
|
||||
setattr (rs, c.RuleCount, len (ss))
|
||||
# Prune empty subrulesets
|
||||
|
Loading…
x
Reference in New Issue
Block a user