subset.py revision 7adbdd624289d2143149c490fef8d9ede32629f6
1ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com# Copyright 2013 Google, Inc. All Rights Reserved. 2ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com# 3ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com# Licensed under the Apache License, Version 2.0(the "License"); 4ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com# you may not use this file except in compliance with the License. 5ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com# You may obtain a copy of the License at 6ec3ed6a5ebf6f2c406d7bcf94b6bc34fcaeb976eepoger@google.com# 7e4fafb146e85cdfcf9d5418597b6818aa0754adatfarina@chromium.org# http://www.apache.org/licenses/LICENSE-2.0 8bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.com# 9a4e13c85b23fe7530ae89a84ef671ebd5e451e80bsalomon@google.com# Unless required by applicable law or agreed to in writing, software 10170bd792e17469769d145b7dc15dea6cd01b7966bsalomon@google.com# distributed under the License is distributed on an "AS IS" BASIS, 11a4e13c85b23fe7530ae89a84ef671ebd5e451e80bsalomon@google.com# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.com# See the License for the specific language governing permissions and 131e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org# limitations under the License. 1451a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com# 151e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org# Google Author(s): Behdad Esfahbod 1651a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com 1780214e26c57c5fea954006400852e8999e201923robertphillips@google.com"""Python OpenType Layout Subsetter. 181e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org 191e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.orgLater grown into full OpenType subsetter, supporting all standard tables. 20d9f2dea5328c9ab455852f2e4928cca7c71c6b05reed@google.com""" 211e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org 2280214e26c57c5fea954006400852e8999e201923robertphillips@google.comimport sys 2380214e26c57c5fea954006400852e8999e201923robertphillips@google.comimport struct 241e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.orgimport time 251e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.orgimport array 2680214e26c57c5fea954006400852e8999e201923robertphillips@google.com 2780214e26c57c5fea954006400852e8999e201923robertphillips@google.comimport fontTools.ttLib 281e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.orgimport fontTools.ttLib.tables 291e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.orgimport fontTools.ttLib.tables.otTables 301e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.orgimport fontTools.cffLib 311e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.orgimport fontTools.misc.psCharStrings 321e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org 33d9f2dea5328c9ab455852f2e4928cca7c71c6b05reed@google.com 341e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.orgdef _add_method(*clazzes): 351e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org """Returns a decorator function that adds a new method to one or 3680214e26c57c5fea954006400852e8999e201923robertphillips@google.com more classes.""" 3780214e26c57c5fea954006400852e8999e201923robertphillips@google.com def wrapper(method): 381e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org for clazz in clazzes: 39d9f2dea5328c9ab455852f2e4928cca7c71c6b05reed@google.com assert clazz.__name__ != 'DefaultTable', 'Oops, table class not found.' 401e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org assert not hasattr(clazz, method.func_name), \ 41d9f2dea5328c9ab455852f2e4928cca7c71c6b05reed@google.com "Oops, class '%s' has method '%s'." % (clazz.__name__, 421e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org method.func_name) 431e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org setattr(clazz, method.func_name, method) 4480214e26c57c5fea954006400852e8999e201923robertphillips@google.com return None 4580214e26c57c5fea954006400852e8999e201923robertphillips@google.com return wrapper 461e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org 47d9f2dea5328c9ab455852f2e4928cca7c71c6b05reed@google.comdef _uniq_sort(l): 481e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org return sorted(set(l)) 491e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org 501e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.orgdef _set_update(s, *others): 511e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org # Jython's set.update only takes one other argument. 521e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org # Emulate real set.update... 531e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org for other in others: 541e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org s.update(other) 5580214e26c57c5fea954006400852e8999e201923robertphillips@google.com 561e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org 571e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org@_add_method(fontTools.ttLib.tables.otTables.Coverage) 581e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.orgdef intersect(self, glyphs): 591e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org "Returns ascending list of matching coverage values." 6080214e26c57c5fea954006400852e8999e201923robertphillips@google.com return [i for i,g in enumerate(self.glyphs) if g in glyphs] 611e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org 62d9f2dea5328c9ab455852f2e4928cca7c71c6b05reed@google.com@_add_method(fontTools.ttLib.tables.otTables.Coverage) 631e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.orgdef intersect_glyphs(self, glyphs): 641e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org "Returns set of intersecting glyphs." 651e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org return set(g for g in self.glyphs if g in glyphs) 661e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org 6780214e26c57c5fea954006400852e8999e201923robertphillips@google.com@_add_method(fontTools.ttLib.tables.otTables.Coverage) 681e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.orgdef subset(self, glyphs): 6980214e26c57c5fea954006400852e8999e201923robertphillips@google.com "Returns ascending list of remaining coverage values." 701e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org indices = self.intersect(glyphs) 71d9f2dea5328c9ab455852f2e4928cca7c71c6b05reed@google.com self.glyphs = [g for g in self.glyphs if g in glyphs] 721e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org return indices 731e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org 74e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org@_add_method(fontTools.ttLib.tables.otTables.Coverage) 751e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.orgdef remap(self, coverage_map): 761e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org "Remaps coverage." 771e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org self.glyphs = [self.glyphs[i] for i in coverage_map] 781e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org 79d9f2dea5328c9ab455852f2e4928cca7c71c6b05reed@google.com@_add_method(fontTools.ttLib.tables.otTables.ClassDef) 80e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.orgdef intersect(self, glyphs): 811e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org "Returns ascending list of matching class values." 821e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org return _uniq_sort( 831e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org ([0] if any(g not in self.classDefs for g in glyphs) else []) + 8480214e26c57c5fea954006400852e8999e201923robertphillips@google.com [v for g,v in self.classDefs.iteritems() if g in glyphs]) 851e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org 8680214e26c57c5fea954006400852e8999e201923robertphillips@google.com@_add_method(fontTools.ttLib.tables.otTables.ClassDef) 8780214e26c57c5fea954006400852e8999e201923robertphillips@google.comdef intersect_class(self, glyphs, klass): 881e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org "Returns set of glyphs matching class." 89d9f2dea5328c9ab455852f2e4928cca7c71c6b05reed@google.com if klass == 0: 901e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org return set(g for g in glyphs if g not in self.classDefs) 911e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org return set(g for g,v in self.classDefs.iteritems() 921e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org if v == klass and g in glyphs) 931e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org 9480214e26c57c5fea954006400852e8999e201923robertphillips@google.com@_add_method(fontTools.ttLib.tables.otTables.ClassDef) 9580214e26c57c5fea954006400852e8999e201923robertphillips@google.comdef subset(self, glyphs, remap=False): 961e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org "Returns ascending list of remaining classes." 9780214e26c57c5fea954006400852e8999e201923robertphillips@google.com self.classDefs = dict((g,v) for g,v in self.classDefs.iteritems() if g in glyphs) 981e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org # Note: while class 0 has the special meaning of "not matched", 991e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org # if no glyph will ever /not match/, we can optimize class 0 out too. 10080214e26c57c5fea954006400852e8999e201923robertphillips@google.com indices = _uniq_sort( 1011e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org ([0] if any(g not in self.classDefs for g in glyphs) else []) + 10280214e26c57c5fea954006400852e8999e201923robertphillips@google.com self.classDefs.values()) 1031e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org if remap: 1041e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org self.remap(indices) 1051e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org return indices 1061e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org 10780214e26c57c5fea954006400852e8999e201923robertphillips@google.com@_add_method(fontTools.ttLib.tables.otTables.ClassDef) 1081e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.orgdef remap(self, class_map): 10980214e26c57c5fea954006400852e8999e201923robertphillips@google.com "Remaps classes." 11080214e26c57c5fea954006400852e8999e201923robertphillips@google.com self.classDefs = dict((g,class_map.index(v)) 1111e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org for g,v in self.classDefs.iteritems()) 112d9f2dea5328c9ab455852f2e4928cca7c71c6b05reed@google.com 1131e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org@_add_method(fontTools.ttLib.tables.otTables.SingleSubst) 1141e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.orgdef closure_glyphs(self, s, cur_glyphs=None): 115bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.com if cur_glyphs == None: cur_glyphs = s.glyphs 116bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.com if self.Format in [1, 2]: 117bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.com s.glyphs.update(v for g,v in self.mapping.iteritems() if g in cur_glyphs) 11880214e26c57c5fea954006400852e8999e201923robertphillips@google.com else: 119bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.com assert 0, "unknown format: %s" % self.Format 120bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.com 121bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.com@_add_method(fontTools.ttLib.tables.otTables.SingleSubst) 122bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.comdef subset_glyphs(self, s): 123bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.com if self.Format in [1, 2]: 124bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.com self.mapping = dict((g,v) for g,v in self.mapping.iteritems() 125bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.com if g in s.glyphs and v in s.glyphs) 12608eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com return bool(self.mapping) 12708eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com else: 12880214e26c57c5fea954006400852e8999e201923robertphillips@google.com assert 0, "unknown format: %s" % self.Format 12980214e26c57c5fea954006400852e8999e201923robertphillips@google.com 13080214e26c57c5fea954006400852e8999e201923robertphillips@google.com@_add_method(fontTools.ttLib.tables.otTables.MultipleSubst) 13180214e26c57c5fea954006400852e8999e201923robertphillips@google.comdef closure_glyphs(self, s, cur_glyphs=None): 13280214e26c57c5fea954006400852e8999e201923robertphillips@google.com if cur_glyphs == None: cur_glyphs = s.glyphs 13380214e26c57c5fea954006400852e8999e201923robertphillips@google.com if self.Format == 1: 13480214e26c57c5fea954006400852e8999e201923robertphillips@google.com indices = self.Coverage.intersect(cur_glyphs) 13580214e26c57c5fea954006400852e8999e201923robertphillips@google.com _set_update(s.glyphs, *(self.Sequence[i].Substitute for i in indices)) 13680214e26c57c5fea954006400852e8999e201923robertphillips@google.com else: 13780214e26c57c5fea954006400852e8999e201923robertphillips@google.com assert 0, "unknown format: %s" % self.Format 13880214e26c57c5fea954006400852e8999e201923robertphillips@google.com 13980214e26c57c5fea954006400852e8999e201923robertphillips@google.com@_add_method(fontTools.ttLib.tables.otTables.MultipleSubst) 14080214e26c57c5fea954006400852e8999e201923robertphillips@google.comdef subset_glyphs(self, s): 14180214e26c57c5fea954006400852e8999e201923robertphillips@google.com if self.Format == 1: 14280214e26c57c5fea954006400852e8999e201923robertphillips@google.com indices = self.Coverage.subset(s.glyphs) 14380214e26c57c5fea954006400852e8999e201923robertphillips@google.com self.Sequence = [self.Sequence[i] for i in indices] 14480214e26c57c5fea954006400852e8999e201923robertphillips@google.com # Now drop rules generating glyphs we don't want 14580214e26c57c5fea954006400852e8999e201923robertphillips@google.com indices = [i for i,seq in enumerate(self.Sequence) 14680214e26c57c5fea954006400852e8999e201923robertphillips@google.com if all(sub in s.glyphs for sub in seq.Substitute)] 1472880df2609eba09b555ca37be04b6ad89290c765Tom Hudson self.Sequence = [self.Sequence[i] for i in indices] 14880214e26c57c5fea954006400852e8999e201923robertphillips@google.com self.Coverage.remap(indices) 14980214e26c57c5fea954006400852e8999e201923robertphillips@google.com self.SequenceCount = len(self.Sequence) 15080214e26c57c5fea954006400852e8999e201923robertphillips@google.com return bool(self.SequenceCount) 15180214e26c57c5fea954006400852e8999e201923robertphillips@google.com else: 1528182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com assert 0, "unknown format: %s" % self.Format 1538182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com 1548182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com@_add_method(fontTools.ttLib.tables.otTables.AlternateSubst) 15580214e26c57c5fea954006400852e8999e201923robertphillips@google.comdef closure_glyphs(self, s, cur_glyphs=None): 15680214e26c57c5fea954006400852e8999e201923robertphillips@google.com if cur_glyphs == None: cur_glyphs = s.glyphs 15780214e26c57c5fea954006400852e8999e201923robertphillips@google.com if self.Format == 1: 15880214e26c57c5fea954006400852e8999e201923robertphillips@google.com _set_update(s.glyphs, *(vlist for g,vlist in self.alternates.iteritems() 15980214e26c57c5fea954006400852e8999e201923robertphillips@google.com if g in cur_glyphs)) 16080214e26c57c5fea954006400852e8999e201923robertphillips@google.com else: 16180214e26c57c5fea954006400852e8999e201923robertphillips@google.com assert 0, "unknown format: %s" % self.Format 1622880df2609eba09b555ca37be04b6ad89290c765Tom Hudson 16380214e26c57c5fea954006400852e8999e201923robertphillips@google.com@_add_method(fontTools.ttLib.tables.otTables.AlternateSubst) 16480214e26c57c5fea954006400852e8999e201923robertphillips@google.comdef subset_glyphs(self, s): 16580214e26c57c5fea954006400852e8999e201923robertphillips@google.com if self.Format == 1: 16680214e26c57c5fea954006400852e8999e201923robertphillips@google.com self.alternates = dict((g,vlist) 1678182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com for g,vlist in self.alternates.iteritems() 1688182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com if g in s.glyphs and 1698182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com all(v in s.glyphs for v in vlist)) 17080214e26c57c5fea954006400852e8999e201923robertphillips@google.com return bool(self.alternates) 17180214e26c57c5fea954006400852e8999e201923robertphillips@google.com else: 17280214e26c57c5fea954006400852e8999e201923robertphillips@google.com assert 0, "unknown format: %s" % self.Format 17380214e26c57c5fea954006400852e8999e201923robertphillips@google.com 17480214e26c57c5fea954006400852e8999e201923robertphillips@google.com@_add_method(fontTools.ttLib.tables.otTables.LigatureSubst) 17580214e26c57c5fea954006400852e8999e201923robertphillips@google.comdef closure_glyphs(self, s, cur_glyphs=None): 17680214e26c57c5fea954006400852e8999e201923robertphillips@google.com if cur_glyphs == None: cur_glyphs = s.glyphs 1772880df2609eba09b555ca37be04b6ad89290c765Tom Hudson if self.Format == 1: 17880214e26c57c5fea954006400852e8999e201923robertphillips@google.com _set_update(s.glyphs, *([seq.LigGlyph for seq in seqs 17980214e26c57c5fea954006400852e8999e201923robertphillips@google.com if all(c in s.glyphs for c in seq.Component)] 18080214e26c57c5fea954006400852e8999e201923robertphillips@google.com for g,seqs in self.ligatures.iteritems() 1818182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com if g in cur_glyphs)) 1828182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com else: 1838182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com assert 0, "unknown format: %s" % self.Format 18480214e26c57c5fea954006400852e8999e201923robertphillips@google.com 18580214e26c57c5fea954006400852e8999e201923robertphillips@google.com@_add_method(fontTools.ttLib.tables.otTables.LigatureSubst) 18680214e26c57c5fea954006400852e8999e201923robertphillips@google.comdef subset_glyphs(self, s): 18708eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com if self.Format == 1: 188e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org self.ligatures = dict((g,v) for g,v in self.ligatures.iteritems() 189607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com if g in s.glyphs) 190607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com self.ligatures = dict((g,[seq for seq in seqs 191607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com if seq.LigGlyph in s.glyphs and 192607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com all(c in s.glyphs for c in seq.Component)]) 193607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com for g,seqs in self.ligatures.iteritems()) 194607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com self.ligatures = dict((g,v) for g,v in self.ligatures.iteritems() if v) 195607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com return bool(self.ligatures) 196607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com else: 197607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com assert 0, "unknown format: %s" % self.Format 198607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com 199607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com@_add_method(fontTools.ttLib.tables.otTables.ReverseChainSingleSubst) 200607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.comdef closure_glyphs(self, s, cur_glyphs=None): 201607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com if cur_glyphs == None: cur_glyphs = s.glyphs 202607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com if self.Format == 1: 203607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com indices = self.Coverage.intersect(cur_glyphs) 204607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com if(not indices or 205607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com not all(c.intersect(s.glyphs) 206607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com for c in self.LookAheadCoverage + self.BacktrackCoverage)): 207607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com return 208607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com s.glyphs.update(self.Substitute[i] for i in indices) 209607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com else: 210607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com assert 0, "unknown format: %s" % self.Format 211607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com 212607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com@_add_method(fontTools.ttLib.tables.otTables.ReverseChainSingleSubst) 213607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.comdef subset_glyphs(self, s): 214607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com if self.Format == 1: 215607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com indices = self.Coverage.subset(s.glyphs) 216607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com self.Substitute = [self.Substitute[i] for i in indices] 217607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com # Now drop rules generating glyphs we don't want 218607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com indices = [i for i,sub in enumerate(self.Substitute) 219607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com if sub in s.glyphs] 220607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com self.Substitute = [self.Substitute[i] for i in indices] 221607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com self.Coverage.remap(indices) 222607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com self.GlyphCount = len(self.Substitute) 223607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com return bool(self.GlyphCount and 224607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com all(c.subset(s.glyphs) 225607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com for c in self.LookAheadCoverage+self.BacktrackCoverage)) 226607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com else: 227607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com assert 0, "unknown format: %s" % self.Format 228607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com 229607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com@_add_method(fontTools.ttLib.tables.otTables.SinglePos) 230607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.comdef subset_glyphs(self, s): 231607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com if self.Format == 1: 232607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com return len(self.Coverage.subset(s.glyphs)) 233e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org elif self.Format == 2: 234e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org indices = self.Coverage.subset(s.glyphs) 235e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org self.Value = [self.Value[i] for i in indices] 236607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com self.ValueCount = len(self.Value) 237e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org return bool(self.ValueCount) 238e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org else: 239e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org assert 0, "unknown format: %s" % self.Format 240e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org 241607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com@_add_method(fontTools.ttLib.tables.otTables.SinglePos) 242607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.comdef prune_post_subset(self, options): 2437b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com if not options.hinting: 2444c2a2f7c5e8ec77771153f94c454adf21fd33805robertphillips@google.com # Drop device tables 245607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com self.ValueFormat &= ~0x00F0 246607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com return True 247e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org 2484c2a2f7c5e8ec77771153f94c454adf21fd33805robertphillips@google.com@_add_method(fontTools.ttLib.tables.otTables.PairPos) 249607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.comdef subset_glyphs(self, s): 250607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com if self.Format == 1: 251607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com indices = self.Coverage.subset(s.glyphs) 252607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com self.PairSet = [self.PairSet[i] for i in indices] 253607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com for p in self.PairSet: 254607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com p.PairValueRecord = [r for r in p.PairValueRecord 255e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org if r.SecondGlyph in s.glyphs] 256607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com p.PairValueCount = len(p.PairValueRecord) 257e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org self.PairSet = [p for p in self.PairSet if p.PairValueCount] 258607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com self.PairSetCount = len(self.PairSet) 259607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com return bool(self.PairSetCount) 260e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org elif self.Format == 2: 261e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org class1_map = self.ClassDef1.subset(s.glyphs, remap=True) 262e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org class2_map = self.ClassDef2.subset(s.glyphs, remap=True) 263e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org self.Class1Record = [self.Class1Record[i] for i in class1_map] 264e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org for c in self.Class1Record: 265e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org c.Class2Record = [c.Class2Record[i] for i in class2_map] 266e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org self.Class1Count = len(class1_map) 267e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org self.Class2Count = len(class2_map) 268e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org return bool(self.Class1Count and 269e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org self.Class2Count and 270e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org self.Coverage.subset(s.glyphs)) 271e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org else: 272e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org assert 0, "unknown format: %s" % self.Format 273e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org 274e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org@_add_method(fontTools.ttLib.tables.otTables.PairPos) 275e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.orgdef prune_post_subset(self, options): 2764c2a2f7c5e8ec77771153f94c454adf21fd33805robertphillips@google.com if not options.hinting: 277607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com # Drop device tables 278cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com self.ValueFormat1 &= ~0x00F0 279d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org self.ValueFormat2 &= ~0x00F0 280cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com return True 2817b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com 2824c2a2f7c5e8ec77771153f94c454adf21fd33805robertphillips@google.com@_add_method(fontTools.ttLib.tables.otTables.CursivePos) 2834c2a2f7c5e8ec77771153f94c454adf21fd33805robertphillips@google.comdef subset_glyphs(self, s): 284e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org if self.Format == 1: 285d6176b0dcacb124539e0cfd051e6d93a9782f020rmistry@google.com indices = self.Coverage.subset(s.glyphs) 2864c2a2f7c5e8ec77771153f94c454adf21fd33805robertphillips@google.com self.EntryExitRecord = [self.EntryExitRecord[i] for i in indices] 2874c2a2f7c5e8ec77771153f94c454adf21fd33805robertphillips@google.com self.EntryExitCount = len(self.EntryExitRecord) 2884c2a2f7c5e8ec77771153f94c454adf21fd33805robertphillips@google.com return bool(self.EntryExitCount) 2894c2a2f7c5e8ec77771153f94c454adf21fd33805robertphillips@google.com else: 290607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com assert 0, "unknown format: %s" % self.Format 291607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com 2927b11289b4e4d117bbcee6d2460b057d0fcf6e437robertphillips@google.com@_add_method(fontTools.ttLib.tables.otTables.Anchor) 293607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.comdef prune_hints(self): 294607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com # Drop device tables / contour anchor point 295607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com self.Format = 1 296607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com 297607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com@_add_method(fontTools.ttLib.tables.otTables.CursivePos) 298607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.comdef prune_post_subset(self, options): 299607fe077c893fdb230e29631be096de614a14e2arobertphillips@google.com if not options.hinting: 300cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com for rec in self.EntryExitRecord: 301cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com if rec.EntryAnchor: rec.EntryAnchor.prune_hints() 302d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org if rec.ExitAnchor: rec.ExitAnchor.prune_hints() 303d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org return True 304d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org 305d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org@_add_method(fontTools.ttLib.tables.otTables.MarkBasePos) 306d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.orgdef subset_glyphs(self, s): 307d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org if self.Format == 1: 308cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com mark_indices = self.MarkCoverage.subset(s.glyphs) 309cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com self.MarkArray.MarkRecord = [self.MarkArray.MarkRecord[i] 310cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com for i in mark_indices] 311cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com self.MarkArray.MarkCount = len(self.MarkArray.MarkRecord) 312cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com base_indices = self.BaseCoverage.subset(s.glyphs) 313cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com self.BaseArray.BaseRecord = [self.BaseArray.BaseRecord[i] 314cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com for i in base_indices] 315cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com self.BaseArray.BaseCount = len(self.BaseArray.BaseRecord) 316cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com # Prune empty classes 317cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com class_indices = _uniq_sort(v.Class for v in self.MarkArray.MarkRecord) 318cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com self.ClassCount = len(class_indices) 319d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org for m in self.MarkArray.MarkRecord: 320cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com m.Class = class_indices.index(m.Class) 321cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com for b in self.BaseArray.BaseRecord: 322cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com b.BaseAnchor = [b.BaseAnchor[i] for i in class_indices] 323cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com return bool(self.ClassCount and 324cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com self.MarkArray.MarkCount and 325cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com self.BaseArray.BaseCount) 326cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com else: 327cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com assert 0, "unknown format: %s" % self.Format 328cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com 329cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com@_add_method(fontTools.ttLib.tables.otTables.MarkBasePos) 330cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.comdef prune_post_subset(self, options): 331cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com if not options.hinting: 332cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com for m in self.MarkArray.MarkRecord: 333cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com m.MarkAnchor.prune_hints() 334cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com for b in self.BaseArray.BaseRecord: 335cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com for a in b.BaseAnchor: 336cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com a.prune_hints() 337cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com return True 338d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org 339cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com@_add_method(fontTools.ttLib.tables.otTables.MarkLigPos) 340cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.comdef subset_glyphs(self, s): 341cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com if self.Format == 1: 342cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com mark_indices = self.MarkCoverage.subset(s.glyphs) 343cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com self.MarkArray.MarkRecord = [self.MarkArray.MarkRecord[i] 344cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com for i in mark_indices] 345cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com self.MarkArray.MarkCount = len(self.MarkArray.MarkRecord) 346cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com ligature_indices = self.LigatureCoverage.subset(s.glyphs) 347cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com self.LigatureArray.LigatureAttach = [self.LigatureArray.LigatureAttach[i] 348d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org for i in ligature_indices] 349cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com self.LigatureArray.LigatureCount = len(self.LigatureArray.LigatureAttach) 350cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com # Prune empty classes 351cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com class_indices = _uniq_sort(v.Class for v in self.MarkArray.MarkRecord) 352cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com self.ClassCount = len(class_indices) 353cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com for m in self.MarkArray.MarkRecord: 354cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com m.Class = class_indices.index(m.Class) 355cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com for l in self.LigatureArray.LigatureAttach: 356cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com for c in l.ComponentRecord: 357cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com c.LigatureAnchor = [c.LigatureAnchor[i] for i in class_indices] 358cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com return bool(self.ClassCount and 359cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com self.MarkArray.MarkCount and 360cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com self.LigatureArray.LigatureCount) 361d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org else: 362cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com assert 0, "unknown format: %s" % self.Format 363cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com 364cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com@_add_method(fontTools.ttLib.tables.otTables.MarkLigPos) 365cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.comdef prune_post_subset(self, options): 366cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com if not options.hinting: 367cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com for m in self.MarkArray.MarkRecord: 368cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com m.MarkAnchor.prune_hints() 369cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com for l in self.LigatureArray.LigatureAttach: 370cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com for c in l.ComponentRecord: 371cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com for a in c.LigatureAnchor: 372cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com a.prune_hints() 373d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org return True 374cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com 375cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com@_add_method(fontTools.ttLib.tables.otTables.MarkMarkPos) 376cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.comdef subset_glyphs(self, s): 377cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com if self.Format == 1: 378d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org mark1_indices = self.Mark1Coverage.subset(s.glyphs) 379cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com self.Mark1Array.MarkRecord = [self.Mark1Array.MarkRecord[i] 380cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com for i in mark1_indices] 381cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com self.Mark1Array.MarkCount = len(self.Mark1Array.MarkRecord) 382100abf49e10544bc4f436bf1f38e6929779621f4bsalomon@google.com mark2_indices = self.Mark2Coverage.subset(s.glyphs) 38308eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com self.Mark2Array.Mark2Record = [self.Mark2Array.Mark2Record[i] 38408eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com for i in mark2_indices] 38508eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com self.Mark2Array.MarkCount = len(self.Mark2Array.Mark2Record) 3862880df2609eba09b555ca37be04b6ad89290c765Tom Hudson # Prune empty classes 38708eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com class_indices = _uniq_sort(v.Class for v in self.Mark1Array.MarkRecord) 38808eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com self.ClassCount = len(class_indices) 3898182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com for m in self.Mark1Array.MarkRecord: 39008eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com m.Class = class_indices.index(m.Class) 39108eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com for b in self.Mark2Array.Mark2Record: 39208eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com b.Mark2Anchor = [b.Mark2Anchor[i] for i in class_indices] 39308eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com return bool(self.ClassCount and 39408eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com self.Mark1Array.MarkCount and 39508eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com self.Mark2Array.MarkCount) 396edf32d5b0e7694833287024e03da38521a0adf05junov@chromium.org else: 397edf32d5b0e7694833287024e03da38521a0adf05junov@chromium.org assert 0, "unknown format: %s" % self.Format 398edf32d5b0e7694833287024e03da38521a0adf05junov@chromium.org 399edf32d5b0e7694833287024e03da38521a0adf05junov@chromium.org@_add_method(fontTools.ttLib.tables.otTables.MarkMarkPos) 400edf32d5b0e7694833287024e03da38521a0adf05junov@chromium.orgdef prune_post_subset(self, options): 401edf32d5b0e7694833287024e03da38521a0adf05junov@chromium.org if not options.hinting: 402edf32d5b0e7694833287024e03da38521a0adf05junov@chromium.org # Drop device tables or contour anchor point 403edf32d5b0e7694833287024e03da38521a0adf05junov@chromium.org for m in self.Mark1Array.MarkRecord: 404edf32d5b0e7694833287024e03da38521a0adf05junov@chromium.org m.MarkAnchor.prune_hints() 405edf32d5b0e7694833287024e03da38521a0adf05junov@chromium.org for b in self.Mark2Array.Mark2Record: 406edf32d5b0e7694833287024e03da38521a0adf05junov@chromium.org for m in rec.Mark2Anchor: 407edf32d5b0e7694833287024e03da38521a0adf05junov@chromium.org m.prune_hints() 408edf32d5b0e7694833287024e03da38521a0adf05junov@chromium.org return True 409edf32d5b0e7694833287024e03da38521a0adf05junov@chromium.org 410edf32d5b0e7694833287024e03da38521a0adf05junov@chromium.org@_add_method(fontTools.ttLib.tables.otTables.SingleSubst, 411edf32d5b0e7694833287024e03da38521a0adf05junov@chromium.org fontTools.ttLib.tables.otTables.MultipleSubst, 412edf32d5b0e7694833287024e03da38521a0adf05junov@chromium.org fontTools.ttLib.tables.otTables.AlternateSubst, 4136fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org fontTools.ttLib.tables.otTables.LigatureSubst, 4146fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org fontTools.ttLib.tables.otTables.ReverseChainSingleSubst, 4156fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org fontTools.ttLib.tables.otTables.SinglePos, 4166fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org fontTools.ttLib.tables.otTables.PairPos, 4176fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org fontTools.ttLib.tables.otTables.CursivePos, 4186fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org fontTools.ttLib.tables.otTables.MarkBasePos, 4196fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org fontTools.ttLib.tables.otTables.MarkLigPos, 4206fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org fontTools.ttLib.tables.otTables.MarkMarkPos) 4216fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.orgdef subset_lookups(self, lookup_indices): 4226fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org pass 4236fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org 4246fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org@_add_method(fontTools.ttLib.tables.otTables.SingleSubst, 4256fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org fontTools.ttLib.tables.otTables.MultipleSubst, 4266fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org fontTools.ttLib.tables.otTables.AlternateSubst, 4276fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org fontTools.ttLib.tables.otTables.LigatureSubst, 4286fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org fontTools.ttLib.tables.otTables.ReverseChainSingleSubst, 4296fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org fontTools.ttLib.tables.otTables.SinglePos, 4306fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org fontTools.ttLib.tables.otTables.PairPos, 4316fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org fontTools.ttLib.tables.otTables.CursivePos, 4326fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org fontTools.ttLib.tables.otTables.MarkBasePos, 4336fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org fontTools.ttLib.tables.otTables.MarkLigPos, 4346fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org fontTools.ttLib.tables.otTables.MarkMarkPos) 4356fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.orgdef collect_lookups(self): 4366fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org return [] 4376fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org 4386fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org@_add_method(fontTools.ttLib.tables.otTables.SingleSubst, 4396fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org fontTools.ttLib.tables.otTables.MultipleSubst, 4406fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org fontTools.ttLib.tables.otTables.AlternateSubst, 4416fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org fontTools.ttLib.tables.otTables.LigatureSubst, 4426fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org fontTools.ttLib.tables.otTables.ContextSubst, 4436fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org fontTools.ttLib.tables.otTables.ChainContextSubst, 4446fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org fontTools.ttLib.tables.otTables.ReverseChainSingleSubst, 4456fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org fontTools.ttLib.tables.otTables.SinglePos, 4466fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org fontTools.ttLib.tables.otTables.PairPos, 4476fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org fontTools.ttLib.tables.otTables.CursivePos, 4486fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org fontTools.ttLib.tables.otTables.MarkBasePos, 4496fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org fontTools.ttLib.tables.otTables.MarkLigPos, 4506fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org fontTools.ttLib.tables.otTables.MarkMarkPos, 4516fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org fontTools.ttLib.tables.otTables.ContextPos, 4526fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org fontTools.ttLib.tables.otTables.ChainContextPos) 4536fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.orgdef prune_pre_subset(self, options): 4546fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org return True 4556fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org 4566fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org@_add_method(fontTools.ttLib.tables.otTables.SingleSubst, 4576fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org fontTools.ttLib.tables.otTables.MultipleSubst, 4586fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org fontTools.ttLib.tables.otTables.AlternateSubst, 4596fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org fontTools.ttLib.tables.otTables.LigatureSubst, 4606fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org fontTools.ttLib.tables.otTables.ReverseChainSingleSubst, 4616fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org fontTools.ttLib.tables.otTables.ContextSubst, 4626fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org fontTools.ttLib.tables.otTables.ChainContextSubst, 4636fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org fontTools.ttLib.tables.otTables.ContextPos, 4646fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org fontTools.ttLib.tables.otTables.ChainContextPos) 4656fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.orgdef prune_post_subset(self, options): 4666fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org return True 4676fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org 4686fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org@_add_method(fontTools.ttLib.tables.otTables.SingleSubst, 4696fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org fontTools.ttLib.tables.otTables.AlternateSubst, 4706fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org fontTools.ttLib.tables.otTables.ReverseChainSingleSubst) 4716fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.orgdef may_have_non_1to1(self): 4726fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org return False 4736fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org 4746fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org@_add_method(fontTools.ttLib.tables.otTables.MultipleSubst, 4756fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org fontTools.ttLib.tables.otTables.LigatureSubst, 4766fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org fontTools.ttLib.tables.otTables.ContextSubst, 4776fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org fontTools.ttLib.tables.otTables.ChainContextSubst) 4786fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.orgdef may_have_non_1to1(self): 4796fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org return True 4806fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org 4816fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org@_add_method(fontTools.ttLib.tables.otTables.ContextSubst, 4826fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org fontTools.ttLib.tables.otTables.ChainContextSubst, 4836fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org fontTools.ttLib.tables.otTables.ContextPos, 4846fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org fontTools.ttLib.tables.otTables.ChainContextPos) 4856fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.orgdef __classify_context(self): 4866fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org 4876fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org class ContextHelper(object): 4886fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org def __init__(self, klass, Format): 4896fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org if klass.__name__.endswith('Subst'): 4906fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org Typ = 'Sub' 4916fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org Type = 'Subst' 4926fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org else: 4936fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org Typ = 'Pos' 4946fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org Type = 'Pos' 4956fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org if klass.__name__.startswith('Chain'): 4966fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org Chain = 'Chain' 4976fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org else: 4986fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org Chain = '' 4996fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org ChainTyp = Chain+Typ 5006fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org 5016fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org self.Typ = Typ 5026fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org self.Type = Type 5036fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org self.Chain = Chain 5046fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org self.ChainTyp = ChainTyp 5056fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org 5066fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org self.LookupRecord = Type+'LookupRecord' 5076fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org 5086fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org if Format == 1: 5096fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org Coverage = lambda r: r.Coverage 5106fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org ChainCoverage = lambda r: r.Coverage 5116fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org ContextData = lambda r:(None,) 5126fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org ChainContextData = lambda r:(None, None, None) 5136fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org RuleData = lambda r:(r.Input,) 51408eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com ChainRuleData = lambda r:(r.Backtrack, r.Input, r.LookAhead) 51508eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com SetRuleData = None 51608eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com ChainSetRuleData = None 51708eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com elif Format == 2: 51808eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com Coverage = lambda r: r.Coverage 51908eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com ChainCoverage = lambda r: r.Coverage 52008eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com ContextData = lambda r:(r.ClassDef,) 52108eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com ChainContextData = lambda r:(r.LookAheadClassDef, 52208eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com r.InputClassDef, 52308eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com r.BacktrackClassDef) 52408eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com RuleData = lambda r:(r.Class,) 52508eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com ChainRuleData = lambda r:(r.LookAhead, r.Input, r.Backtrack) 52608eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com def SetRuleData(r, d):(r.Class,) = d 52708eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com def ChainSetRuleData(r, d):(r.LookAhead, r.Input, r.Backtrack) = d 52808eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com elif Format == 3: 52908eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com Coverage = lambda r: r.Coverage[0] 53008eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com ChainCoverage = lambda r: r.InputCoverage[0] 53108eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com ContextData = None 53208eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com ChainContextData = None 53308eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com RuleData = lambda r: r.Coverage 53408eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com ChainRuleData = lambda r:(r.LookAheadCoverage + 53508eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com r.InputCoverage + 53608eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com r.BacktrackCoverage) 53708eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com SetRuleData = None 53808eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com ChainSetRuleData = None 53908eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com else: 54008eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com assert 0, "unknown format: %s" % Format 54108eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com 54208eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com if Chain: 54308eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com self.Coverage = ChainCoverage 54408eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com self.ContextData = ChainContextData 54508eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com self.RuleData = ChainRuleData 54608eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com self.SetRuleData = ChainSetRuleData 54708eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com else: 54808eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com self.Coverage = Coverage 54908eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com self.ContextData = ContextData 55008eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com self.RuleData = RuleData 55108eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com self.SetRuleData = SetRuleData 55208eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com 55308eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com if Format == 1: 55408eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com self.Rule = ChainTyp+'Rule' 55508eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com self.RuleCount = ChainTyp+'RuleCount' 55608eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com self.RuleSet = ChainTyp+'RuleSet' 55708eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com self.RuleSetCount = ChainTyp+'RuleSetCount' 55808eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com self.Intersect = lambda glyphs, c, r: [r] if r in glyphs else [] 55908eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com elif Format == 2: 56008eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com self.Rule = ChainTyp+'ClassRule' 56108eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com self.RuleCount = ChainTyp+'ClassRuleCount' 56208eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com self.RuleSet = ChainTyp+'ClassSet' 56308eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com self.RuleSetCount = ChainTyp+'ClassSetCount' 56408eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com self.Intersect = lambda glyphs, c, r: c.intersect_class(glyphs, r) 56508eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com 56608eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com self.ClassDef = 'InputClassDef' if Chain else 'ClassDef' 56708eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com self.Input = 'Input' if Chain else 'Class' 56808eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com 56908eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com if self.Format not in [1, 2, 3]: 57008eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com return None # Don't shoot the messenger; let it go 57108eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com if not hasattr(self.__class__, "__ContextHelpers"): 57208eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com self.__class__.__ContextHelpers = {} 57308eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com if self.Format not in self.__class__.__ContextHelpers: 57408eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com helper = ContextHelper(self.__class__, self.Format) 57508eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com self.__class__.__ContextHelpers[self.Format] = helper 57608eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com return self.__class__.__ContextHelpers[self.Format] 57708eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com 57808eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com@_add_method(fontTools.ttLib.tables.otTables.ContextSubst, 57908eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com fontTools.ttLib.tables.otTables.ChainContextSubst) 58008eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.comdef closure_glyphs(self, s, cur_glyphs=None): 58108eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com if cur_glyphs == None: cur_glyphs = s.glyphs 58208eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com c = self.__classify_context() 58308eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com 58408eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com indices = c.Coverage(self).intersect(s.glyphs) 58508eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com if not indices: 58608eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com return [] 58708eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com cur_glyphs = c.Coverage(self).intersect_glyphs(s.glyphs); 58808eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com 58908eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com if self.Format == 1: 59008eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com ContextData = c.ContextData(self) 59108eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com rss = getattr(self, c.RuleSet) 59208eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com for i in indices: 59308eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com if not rss[i]: continue 59408eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com for r in getattr(rss[i], c.Rule): 59508eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com if not r: continue 59608eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com if all(all(c.Intersect(s.glyphs, cd, k) for k in klist) 59708eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com for cd,klist in zip(ContextData, c.RuleData(r))): 59808eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com chaos = False 59908eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com for ll in getattr(r, c.LookupRecord): 60008eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com if not ll: continue 60108eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com seqi = ll.SequenceIndex 60208eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com if chaos: 60308eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com pos_glyphs = s.glyphs 60408eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com else: 60508eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com if seqi == 0: 60608eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com pos_glyphs = set([c.Coverage(self).glyphs[i]]) 60708eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com else: 60808eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com pos_glyphs = set([r.Input[seqi - 1]]) 60908eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com lookup = s.table.LookupList.Lookup[ll.LookupListIndex] 61008eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com chaos = chaos or lookup.may_have_non_1to1() 61108eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com lookup.closure_glyphs(s, cur_glyphs=pos_glyphs) 61208eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com elif self.Format == 2: 61308eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com ClassDef = getattr(self, c.ClassDef) 61408eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com indices = ClassDef.intersect(cur_glyphs) 61508eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com ContextData = c.ContextData(self) 61608eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com rss = getattr(self, c.RuleSet) 61708eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com for i in indices: 618cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com if not rss[i]: continue 6198cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org for r in getattr(rss[i], c.Rule): 6208cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org if not r: continue 6218cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org if all(all(c.Intersect(s.glyphs, cd, k) for k in klist) 6228cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org for cd,klist in zip(ContextData, c.RuleData(r))): 6238cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org chaos = False 6248cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org for ll in getattr(r, c.LookupRecord): 6258cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org if not ll: continue 6268cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org seqi = ll.SequenceIndex 6278cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org if chaos: 6288cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org pos_glyphs = s.glyphs 6298cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org else: 6308cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org if seqi == 0: 6318cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org pos_glyphs = ClassDef.intersect_class(cur_glyphs, i) 6328cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org else: 6338cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org pos_glyphs = ClassDef.intersect_class(s.glyphs, 6348cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org getattr(r, c.Input)[seqi - 1]) 6358cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org lookup = s.table.LookupList.Lookup[ll.LookupListIndex] 6368cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org chaos = chaos or lookup.may_have_non_1to1() 6378cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org lookup.closure_glyphs(s, cur_glyphs=pos_glyphs) 6388cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org elif self.Format == 3: 6398cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org if not all(x.intersect(s.glyphs) for x in c.RuleData(self)): 6408cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org return [] 641306ab9d5de38f2a547fd1d69aedbe69b5c6617ccskia.committer@gmail.com r = self 6428cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org chaos = False 6438cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org for ll in getattr(r, c.LookupRecord): 6448cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org if not ll: continue 6458cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org seqi = ll.SequenceIndex 6468cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org if chaos: 6478cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org pos_glyphs = s.glyphs 6488cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org else: 6498cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org if seqi == 0: 6508cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org pos_glyphs = cur_glyphs 6518cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org else: 6528cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org pos_glyphs = r.InputCoverage[seqi].intersect_glyphs(s.glyphs) 6538cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org lookup = s.table.LookupList.Lookup[ll.LookupListIndex] 6548cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org chaos = chaos or lookup.may_have_non_1to1() 6558cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org lookup.closure_glyphs(s, cur_glyphs=pos_glyphs) 6568cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org else: 6578cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org assert 0, "unknown format: %s" % self.Format 6588cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org 6598cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org@_add_method(fontTools.ttLib.tables.otTables.ContextSubst, 6608cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org fontTools.ttLib.tables.otTables.ContextPos, 6618cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org fontTools.ttLib.tables.otTables.ChainContextSubst, 6628cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org fontTools.ttLib.tables.otTables.ChainContextPos) 6638cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.orgdef subset_glyphs(self, s): 6648cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org c = self.__classify_context() 6658cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org 6668cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org if self.Format == 1: 6678cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org indices = self.Coverage.subset(s.glyphs) 6688cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org rss = getattr(self, c.RuleSet) 6698cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org rss = [rss[i] for i in indices] 6708cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org for rs in rss: 6718cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org if not rs: continue 6728cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org ss = getattr(rs, c.Rule) 6738cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org ss = [r for r in ss 6748cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org if r and all(all(g in s.glyphs for g in glist) 6758cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org for glist in c.RuleData(r))] 6768cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org setattr(rs, c.Rule, ss) 6778cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org setattr(rs, c.RuleCount, len(ss)) 6788cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org # Prune empty subrulesets 6798cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org rss = [rs for rs in rss if rs and getattr(rs, c.Rule)] 6808cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org setattr(self, c.RuleSet, rss) 6818cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org setattr(self, c.RuleSetCount, len(rss)) 6828cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org return bool(rss) 6838cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org elif self.Format == 2: 6848cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org if not self.Coverage.subset(s.glyphs): 6858cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org return False 6868cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org indices = getattr(self, c.ClassDef).subset(self.Coverage.glyphs, 6878cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org remap=False) 6888cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org rss = getattr(self, c.RuleSet) 6898cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org rss = [rss[i] for i in indices] 6908cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org ContextData = c.ContextData(self) 6918cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org klass_maps = [x.subset(s.glyphs, remap=True) for x in ContextData] 6928cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org for rs in rss: 6938cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org if not rs: continue 6948cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org ss = getattr(rs, c.Rule) 6958cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org ss = [r for r in ss 6968cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org if r and all(all(k in klass_map for k in klist) 6978cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org for klass_map,klist in zip(klass_maps, c.RuleData(r)))] 6988cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org setattr(rs, c.Rule, ss) 6998cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org setattr(rs, c.RuleCount, len(ss)) 7008cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org 7018cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org # Remap rule classes 7028cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org for r in ss: 7038cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org c.SetRuleData(r, [[klass_map.index(k) for k in klist] 7048cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org for klass_map,klist in zip(klass_maps, c.RuleData(r))]) 7058cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org # Prune empty subrulesets 7068cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org rss = [rs for rs in rss if rs and getattr(rs, c.Rule)] 7078cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org setattr(self, c.RuleSet, rss) 7088cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org setattr(self, c.RuleSetCount, len(rss)) 7098cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org return bool(rss) 7108cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org elif self.Format == 3: 7118cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org return all(x.subset(s.glyphs) for x in c.RuleData(self)) 7128cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org else: 7138cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org assert 0, "unknown format: %s" % self.Format 7148cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org 7158cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org@_add_method(fontTools.ttLib.tables.otTables.ContextSubst, 7168cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org fontTools.ttLib.tables.otTables.ChainContextSubst, 7178cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org fontTools.ttLib.tables.otTables.ContextPos, 7188cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org fontTools.ttLib.tables.otTables.ChainContextPos) 7198cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.orgdef subset_lookups(self, lookup_indices): 7208cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org c = self.__classify_context() 7218cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org 7228cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org if self.Format in [1, 2]: 7238cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org for rs in getattr(self, c.RuleSet): 7248cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org if not rs: continue 7258cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org for r in getattr(rs, c.Rule): 7268cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org if not r: continue 7278cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org setattr(r, c.LookupRecord, 7288cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org [ll for ll in getattr(r, c.LookupRecord) 7298cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org if ll and ll.LookupListIndex in lookup_indices]) 7308cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org for ll in getattr(r, c.LookupRecord): 7318cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org if not ll: continue 7328cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org ll.LookupListIndex = lookup_indices.index(ll.LookupListIndex) 7338cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org elif self.Format == 3: 7348cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org setattr(self, c.LookupRecord, 7358cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org [ll for ll in getattr(self, c.LookupRecord) 7368cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org if ll and ll.LookupListIndex in lookup_indices]) 7378cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org for ll in getattr(self, c.LookupRecord): 7388cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org if not ll: continue 7398cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org ll.LookupListIndex = lookup_indices.index(ll.LookupListIndex) 7408cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org else: 7418cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org assert 0, "unknown format: %s" % self.Format 7428cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org 7438cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org@_add_method(fontTools.ttLib.tables.otTables.ContextSubst, 7448cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org fontTools.ttLib.tables.otTables.ChainContextSubst, 7458cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org fontTools.ttLib.tables.otTables.ContextPos, 7468cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org fontTools.ttLib.tables.otTables.ChainContextPos) 7478cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.orgdef collect_lookups(self): 7488cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org c = self.__classify_context() 7498cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org 7508cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org if self.Format in [1, 2]: 7518cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org return [ll.LookupListIndex 7528cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org for rs in getattr(self, c.RuleSet) if rs 7538cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org for r in getattr(rs, c.Rule) if r 7548cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org for ll in getattr(r, c.LookupRecord) if ll] 7558cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org elif self.Format == 3: 7568cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org return [ll.LookupListIndex 7578cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org for ll in getattr(self, c.LookupRecord) if ll] 7588cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org else: 7598cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org assert 0, "unknown format: %s" % self.Format 7608cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org 7618cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org@_add_method(fontTools.ttLib.tables.otTables.ExtensionSubst) 7628cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.orgdef closure_glyphs(self, s, cur_glyphs=None): 7638cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org if self.Format == 1: 7648cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org self.ExtSubTable.closure_glyphs(s, cur_glyphs) 7658cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org else: 7668cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org assert 0, "unknown format: %s" % self.Format 7678cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org 7688cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org@_add_method(fontTools.ttLib.tables.otTables.ExtensionSubst) 7698cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.orgdef may_have_non_1to1(self): 7708cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org if self.Format == 1: 7718cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org return self.ExtSubTable.may_have_non_1to1() 7728cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org else: 7738cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org assert 0, "unknown format: %s" % self.Format 7748cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org 7758cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org@_add_method(fontTools.ttLib.tables.otTables.ExtensionSubst, 7768cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org fontTools.ttLib.tables.otTables.ExtensionPos) 7778cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.orgdef prune_pre_subset(self, options): 7788cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org if self.Format == 1: 7798cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org return self.ExtSubTable.prune_pre_subset(options) 7808cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org else: 7818cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org assert 0, "unknown format: %s" % self.Format 7828cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org 7838cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org@_add_method(fontTools.ttLib.tables.otTables.ExtensionSubst, 7848cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org fontTools.ttLib.tables.otTables.ExtensionPos) 7858cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.orgdef subset_glyphs(self, s): 7868cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org if self.Format == 1: 7878cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org return self.ExtSubTable.subset_glyphs(s) 7888cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org else: 7898cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org assert 0, "unknown format: %s" % self.Format 7908cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org 7918cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org@_add_method(fontTools.ttLib.tables.otTables.ExtensionSubst, 7928cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org fontTools.ttLib.tables.otTables.ExtensionPos) 7938cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.orgdef prune_post_subset(self, options): 7948cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org if self.Format == 1: 7958cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org return self.ExtSubTable.prune_post_subset(options) 7968cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org else: 79751a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com assert 0, "unknown format: %s" % self.Format 79851a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com 799a4e13c85b23fe7530ae89a84ef671ebd5e451e80bsalomon@google.com@_add_method(fontTools.ttLib.tables.otTables.ExtensionSubst, 800705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.com fontTools.ttLib.tables.otTables.ExtensionPos) 801705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.comdef subset_lookups(self, lookup_indices): 802705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.com if self.Format == 1: 803705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.com return self.ExtSubTable.subset_lookups(lookup_indices) 804705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.com else: 805705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.com assert 0, "unknown format: %s" % self.Format 806705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.com 807705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.com@_add_method(fontTools.ttLib.tables.otTables.ExtensionSubst, 808705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.com fontTools.ttLib.tables.otTables.ExtensionPos) 809705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.comdef collect_lookups(self): 81051a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com if self.Format == 1: 811705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.com return self.ExtSubTable.collect_lookups() 812705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.com else: 813e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org assert 0, "unknown format: %s" % self.Format 814e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org 815705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.com@_add_method(fontTools.ttLib.tables.otTables.Lookup) 816e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.orgdef closure_glyphs(self, s, cur_glyphs=None): 817e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org for st in self.SubTable: 818e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org if not st: continue 819e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org st.closure_glyphs(s, cur_glyphs) 820e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org 821705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.com@_add_method(fontTools.ttLib.tables.otTables.Lookup) 82251a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.comdef prune_pre_subset(self, options): 82351a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com ret = False 824705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.com for st in self.SubTable: 825705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.com if not st: continue 826705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.com if st.prune_pre_subset(options): ret = True 827705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.com return ret 828705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.com 829705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.com@_add_method(fontTools.ttLib.tables.otTables.Lookup) 830705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.comdef subset_glyphs(self, s): 831705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.com self.SubTable = [st for st in self.SubTable if st and st.subset_glyphs(s)] 832705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.com self.SubTableCount = len(self.SubTable) 83351a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com return bool(self.SubTableCount) 83451a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com 835705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.com@_add_method(fontTools.ttLib.tables.otTables.Lookup) 83651a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.comdef prune_post_subset(self, options): 83751a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com ret = False 838705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.com for st in self.SubTable: 839705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.com if not st: continue 840705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.com if st.prune_post_subset(options): ret = True 841705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.com return ret 84251a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com 84351a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com@_add_method(fontTools.ttLib.tables.otTables.Lookup) 8448182fa0cac76e7e6d583aebba060229230516887bsalomon@google.comdef subset_lookups(self, lookup_indices): 8458182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com for s in self.SubTable: 8468182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com s.subset_lookups(lookup_indices) 8478182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com 8488182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com@_add_method(fontTools.ttLib.tables.otTables.Lookup) 849e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.orgdef collect_lookups(self): 850e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org return _uniq_sort(sum((st.collect_lookups() for st in self.SubTable 851e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org if st), [])) 8528182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com 8538182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com@_add_method(fontTools.ttLib.tables.otTables.Lookup) 8548182fa0cac76e7e6d583aebba060229230516887bsalomon@google.comdef may_have_non_1to1(self): 8558182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com return any(st.may_have_non_1to1() for st in self.SubTable if st) 8568182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com 8578182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com@_add_method(fontTools.ttLib.tables.otTables.LookupList) 8588182fa0cac76e7e6d583aebba060229230516887bsalomon@google.comdef prune_pre_subset(self, options): 85951a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com ret = False 86051a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com for l in self.Lookup: 86151a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com if not l: continue 8628182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com if l.prune_pre_subset(options): ret = True 86351a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com return ret 86451a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com 86551a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com@_add_method(fontTools.ttLib.tables.otTables.LookupList) 86651a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.comdef subset_glyphs(self, s): 867e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org "Returns the indices of nonempty lookups." 86851a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com return [i for i,l in enumerate(self.Lookup) if l and l.subset_glyphs(s)] 8698182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com 870e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org@_add_method(fontTools.ttLib.tables.otTables.LookupList) 871e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.orgdef prune_post_subset(self, options): 8728182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com ret = False 873e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org for l in self.Lookup: 874e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org if not l: continue 875e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org if l.prune_post_subset(options): ret = True 8768182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com return ret 87751a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com 8788182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com@_add_method(fontTools.ttLib.tables.otTables.LookupList) 87951a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.comdef subset_lookups(self, lookup_indices): 88051a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com self.Lookup = [self.Lookup[i] for i in lookup_indices 88151a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com if i < self.LookupCount] 88251a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com self.LookupCount = len(self.Lookup) 8838ccf590b89cec1a5974b6f4b7b49ca67cc5036cfskia.committer@gmail.com for l in self.Lookup: 88451a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com l.subset_lookups(lookup_indices) 88551a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com 88651a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com@_add_method(fontTools.ttLib.tables.otTables.LookupList) 88751a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.comdef closure_lookups(self, lookup_indices): 88851a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com lookup_indices = _uniq_sort(lookup_indices) 88951a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com recurse = lookup_indices 89051a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com while True: 89151a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com recurse_lookups = sum((self.Lookup[i].collect_lookups() 89251a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com for i in recurse if i < self.LookupCount), []) 89351a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com recurse_lookups = [l for l in recurse_lookups 89451a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com if l not in lookup_indices and l < self.LookupCount] 89551a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com if not recurse_lookups: 89651a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com return _uniq_sort(lookup_indices) 89751a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com recurse_lookups = _uniq_sort(recurse_lookups) 89851a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com lookup_indices.extend(recurse_lookups) 89951a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com recurse = recurse_lookups 90051a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com 90151a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com@_add_method(fontTools.ttLib.tables.otTables.Feature) 90251a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.comdef subset_lookups(self, lookup_indices): 90351a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com self.LookupListIndex = [l for l in self.LookupListIndex 90451a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com if l in lookup_indices] 90551a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com # Now map them. 90651a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com self.LookupListIndex = [lookup_indices.index(l) 90751a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com for l in self.LookupListIndex] 90851a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com self.LookupCount = len(self.LookupListIndex) 90951a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com return self.LookupCount 91051a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com 91151a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com@_add_method(fontTools.ttLib.tables.otTables.Feature) 912705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.comdef collect_lookups(self): 913705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.com return self.LookupListIndex[:] 914705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.com 91551a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com@_add_method(fontTools.ttLib.tables.otTables.FeatureList) 91651a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.comdef subset_lookups(self, lookup_indices): 91751a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com "Returns the indices of nonempty features." 91851a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com feature_indices = [i for i,f in enumerate(self.FeatureRecord) 91951a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com if f.Feature.subset_lookups(lookup_indices)] 92051a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com self.subset_features(feature_indices) 921e0e7cfe44bb9d66d76120a79e5275c294bacaa22commit-bot@chromium.org return feature_indices 92251a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com 92351a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com@_add_method(fontTools.ttLib.tables.otTables.FeatureList) 92451a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.comdef collect_lookups(self, feature_indices): 92551a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com return _uniq_sort(sum((self.FeatureRecord[i].Feature.collect_lookups() 92651a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com for i in feature_indices 92751a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com if i < self.FeatureCount), [])) 92851a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com 92951a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com@_add_method(fontTools.ttLib.tables.otTables.FeatureList) 93051a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.comdef subset_features(self, feature_indices): 93151a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com self.FeatureRecord = [self.FeatureRecord[i] for i in feature_indices] 93251a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com self.FeatureCount = len(self.FeatureRecord) 93351a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com return bool(self.FeatureCount) 93451a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com 9358ccf590b89cec1a5974b6f4b7b49ca67cc5036cfskia.committer@gmail.com@_add_method(fontTools.ttLib.tables.otTables.DefaultLangSys, 93651a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com fontTools.ttLib.tables.otTables.LangSys) 93751a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.comdef subset_features(self, feature_indices): 9388ccf590b89cec1a5974b6f4b7b49ca67cc5036cfskia.committer@gmail.com if self.ReqFeatureIndex in feature_indices: 93951a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com self.ReqFeatureIndex = feature_indices.index(self.ReqFeatureIndex) 94051a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com else: 94151a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com self.ReqFeatureIndex = 65535 94251a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com self.FeatureIndex = [f for f in self.FeatureIndex if f in feature_indices] 94351a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com # Now map them. 94451a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com self.FeatureIndex = [feature_indices.index(f) for f in self.FeatureIndex 94551a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com if f in feature_indices] 94651a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com self.FeatureCount = len(self.FeatureIndex) 94751a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com return bool(self.FeatureCount or self.ReqFeatureIndex != 65535) 948705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.com 949e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org@_add_method(fontTools.ttLib.tables.otTables.DefaultLangSys, 950705e84094494613a4659fcabe29f76eb003f9809bsalomon@google.com fontTools.ttLib.tables.otTables.LangSys) 95151a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.comdef collect_features(self): 95251a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com feature_indices = self.FeatureIndex[:] 95351a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com if self.ReqFeatureIndex != 65535: 95451a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com feature_indices.append(self.ReqFeatureIndex) 95551a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com return _uniq_sort(feature_indices) 956a444430281ea35cb76fb42516978b4a93221c2c7bsalomon@google.com 957a444430281ea35cb76fb42516978b4a93221c2c7bsalomon@google.com@_add_method(fontTools.ttLib.tables.otTables.Script) 958a444430281ea35cb76fb42516978b4a93221c2c7bsalomon@google.comdef subset_features(self, feature_indices): 959a444430281ea35cb76fb42516978b4a93221c2c7bsalomon@google.com if(self.DefaultLangSys and 960a444430281ea35cb76fb42516978b4a93221c2c7bsalomon@google.com not self.DefaultLangSys.subset_features(feature_indices)): 9618182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com self.DefaultLangSys = None 96251a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com self.LangSysRecord = [l for l in self.LangSysRecord 9638182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com if l.LangSys.subset_features(feature_indices)] 964d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org self.LangSysCount = len(self.LangSysRecord) 96551a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com return bool(self.LangSysCount or self.DefaultLangSys) 966c490f801b063a0837501feab3d12b73d71f46312jvanverth@google.com 9672880df2609eba09b555ca37be04b6ad89290c765Tom Hudson@_add_method(fontTools.ttLib.tables.otTables.Script) 96834cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.comdef collect_features(self): 96934cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com feature_indices = [l.LangSys.collect_features() for l in self.LangSysRecord] 97034cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com if self.DefaultLangSys: 971d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org feature_indices.append(self.DefaultLangSys.collect_features()) 97234cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com return _uniq_sort(sum(feature_indices, [])) 97334cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com 97451a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com@_add_method(fontTools.ttLib.tables.otTables.ScriptList) 975d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.orgdef subset_features(self, feature_indices): 976d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org self.ScriptRecord = [s for s in self.ScriptRecord 97751a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com if s.Script.subset_features(feature_indices)] 97851a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com self.ScriptCount = len(self.ScriptRecord) 97951a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com return bool(self.ScriptCount) 98051a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com 98151a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com@_add_method(fontTools.ttLib.tables.otTables.ScriptList) 98251a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.comdef collect_features(self): 98349f085dddff10473b6ebf832a974288300224e60bsalomon return _uniq_sort(sum((s.Script.collect_features() 9848182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com for s in self.ScriptRecord), [])) 98551a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com 98651a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com@_add_method(fontTools.ttLib.getTableClass('GSUB')) 98734cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.comdef closure_glyphs(self, s): 98849f085dddff10473b6ebf832a974288300224e60bsalomon s.table = self.table 98934cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com feature_indices = self.table.ScriptList.collect_features() 99034cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com lookup_indices = self.table.FeatureList.collect_lookups(feature_indices) 99134cd70a5810b3cf37b44de1ce080a911a8b342c8bsalomon@google.com while True: 99251a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com orig_glyphs = s.glyphs.copy() 99351a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com for i in lookup_indices: 99451a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com if i >= self.table.LookupList.LookupCount: continue 99551a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com if not self.table.LookupList.Lookup[i]: continue 99651a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com self.table.LookupList.Lookup[i].closure_glyphs(s) 9978182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com if orig_glyphs == s.glyphs: 99851a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com break 9998182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com del s.table 10008182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com 100151a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com@_add_method(fontTools.ttLib.getTableClass('GSUB'), 100251a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com fontTools.ttLib.getTableClass('GPOS')) 100351a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.comdef subset_glyphs(self, s): 100451a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com s.glyphs = s.glyphs_gsubed 10058182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com lookup_indices = self.table.LookupList.subset_glyphs(s) 10068182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com self.subset_lookups(lookup_indices) 100751a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com self.prune_lookups() 1008e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org return True 1009e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org 1010e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org@_add_method(fontTools.ttLib.getTableClass('GSUB'), 101151a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com fontTools.ttLib.getTableClass('GPOS')) 101251a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.comdef subset_lookups(self, lookup_indices): 101351a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com """Retrains specified lookups, then removes empty features, language 1014d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org systems, and scripts.""" 1015d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org self.table.LookupList.subset_lookups(lookup_indices) 1016d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org feature_indices = self.table.FeatureList.subset_lookups(lookup_indices) 1017d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org self.table.ScriptList.subset_features(feature_indices) 1018d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org 1019d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org@_add_method(fontTools.ttLib.getTableClass('GSUB'), 1020d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org fontTools.ttLib.getTableClass('GPOS')) 1021d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.orgdef prune_lookups(self): 1022d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org "Remove unreferenced lookups" 1023d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org feature_indices = self.table.ScriptList.collect_features() 1024d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org lookup_indices = self.table.FeatureList.collect_lookups(feature_indices) 1025d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org lookup_indices = self.table.LookupList.closure_lookups(lookup_indices) 1026d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org self.subset_lookups(lookup_indices) 1027d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org 1028d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org@_add_method(fontTools.ttLib.getTableClass('GSUB'), 1029d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org fontTools.ttLib.getTableClass('GPOS')) 1030d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.orgdef subset_feature_tags(self, feature_tags): 1031d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org feature_indices = [i for i,f in 1032d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org enumerate(self.table.FeatureList.FeatureRecord) 1033d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org if f.FeatureTag in feature_tags] 1034d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org self.table.FeatureList.subset_features(feature_indices) 1035d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org self.table.ScriptList.subset_features(feature_indices) 1036d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org 1037d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org@_add_method(fontTools.ttLib.getTableClass('GSUB'), 1038d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org fontTools.ttLib.getTableClass('GPOS')) 1039d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.orgdef prune_pre_subset(self, options): 1040d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org if '*' not in options.layout_features: 1041d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org self.subset_feature_tags(options.layout_features) 1042d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org self.prune_lookups() 1043d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org self.table.LookupList.prune_pre_subset(options); 1044d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org return True 1045d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org 1046d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org@_add_method(fontTools.ttLib.getTableClass('GSUB'), 1047d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org fontTools.ttLib.getTableClass('GPOS')) 1048d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.orgdef prune_post_subset(self, options): 1049d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org self.table.LookupList.prune_post_subset(options); 1050d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org return True 1051d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org 1052d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org@_add_method(fontTools.ttLib.getTableClass('GDEF')) 1053d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.orgdef subset_glyphs(self, s): 1054d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org glyphs = s.glyphs_gsubed 1055d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org table = self.table 1056d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org if table.LigCaretList: 1057d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org indices = table.LigCaretList.Coverage.subset(glyphs) 1058d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org table.LigCaretList.LigGlyph = [table.LigCaretList.LigGlyph[i] 1059d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org for i in indices] 1060d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org table.LigCaretList.LigGlyphCount = len(table.LigCaretList.LigGlyph) 1061d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org if not table.LigCaretList.LigGlyphCount: 1062d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org table.LigCaretList = None 1063d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org if table.MarkAttachClassDef: 1064d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org table.MarkAttachClassDef.classDefs = dict((g,v) for g,v in 1065d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org table.MarkAttachClassDef. 1066d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org classDefs.iteritems() 1067d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org if g in glyphs) 1068d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org if not table.MarkAttachClassDef.classDefs: 1069d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org table.MarkAttachClassDef = None 1070d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org if table.GlyphClassDef: 1071d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org table.GlyphClassDef.classDefs = dict((g,v) for g,v in 1072d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org table.GlyphClassDef. 1073d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org classDefs.iteritems() 1074d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org if g in glyphs) 1075d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org if not table.GlyphClassDef.classDefs: 1076d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org table.GlyphClassDef = None 1077d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org if table.AttachList: 1078d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org indices = table.AttachList.Coverage.subset(glyphs) 1079d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org table.AttachList.AttachPoint = [table.AttachList.AttachPoint[i] 1080d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org for i in indices] 1081d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org table.AttachList.GlyphCount = len(table.AttachList.AttachPoint) 1082d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org if not table.AttachList.GlyphCount: 1083d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org table.AttachList = None 1084d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org return bool(table.LigCaretList or 1085d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org table.MarkAttachClassDef or 1086d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org table.GlyphClassDef or 1087d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org table.AttachList) 1088d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org 1089d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org@_add_method(fontTools.ttLib.getTableClass('kern')) 1090d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.orgdef prune_pre_subset(self, options): 1091d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org # Prune unknown kern table types 1092d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org self.kernTables = [t for t in self.kernTables if hasattr(t, 'kernTable')] 1093d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org return bool(self.kernTables) 1094d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org 1095d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org@_add_method(fontTools.ttLib.getTableClass('kern')) 1096d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.orgdef subset_glyphs(self, s): 1097d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org glyphs = s.glyphs_gsubed 1098d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org for t in self.kernTables: 1099d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org t.kernTable = dict(((a,b),v) for (a,b),v in t.kernTable.iteritems() 1100d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org if a in glyphs and b in glyphs) 1101d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org self.kernTables = [t for t in self.kernTables if t.kernTable] 1102d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org return bool(self.kernTables) 1103d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org 1104d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org@_add_method(fontTools.ttLib.getTableClass('vmtx'), 1105d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org fontTools.ttLib.getTableClass('hmtx')) 1106d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.orgdef subset_glyphs(self, s): 1107d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org self.metrics = dict((g,v) for g,v in self.metrics.iteritems() if g in s.glyphs) 1108d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org return bool(self.metrics) 1109d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org 1110d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org@_add_method(fontTools.ttLib.getTableClass('hdmx')) 1111d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.orgdef subset_glyphs(self, s): 1112d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org self.hdmx = dict((sz,_dict((g,v) for g,v in l.iteritems() if g in s.glyphs)) 1113d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org for sz,l in self.hdmx.iteritems()) 1114d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org return bool(self.hdmx) 1115d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org 1116d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org@_add_method(fontTools.ttLib.getTableClass('VORG')) 1117d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.orgdef subset_glyphs(self, s): 1118d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org self.VOriginRecords = dict((g,v) for g,v in self.VOriginRecords.iteritems() 1119d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org if g in s.glyphs) 1120d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org self.numVertOriginYMetrics = len(self.VOriginRecords) 1121d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org return True # Never drop; has default metrics 1122d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org 1123d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org@_add_method(fontTools.ttLib.getTableClass('post')) 1124d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.orgdef prune_pre_subset(self, options): 1125d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org if not options.glyph_names: 1126d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org self.formatType = 3.0 1127d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org return True 1128d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org 1129d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org@_add_method(fontTools.ttLib.getTableClass('post')) 1130d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.orgdef subset_glyphs(self, s): 1131d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org self.extraNames = [] # This seems to do it 11322880df2609eba09b555ca37be04b6ad89290c765Tom Hudson return True 1133d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org 1134d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org@_add_method(fontTools.ttLib.getTableModule('glyf').Glyph) 1135d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.orgdef getComponentNamesFast(self, glyfTable): 1136d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org if not self.data or struct.unpack(">h", self.data[:2])[0] >= 0: 1137d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org return [] # Not composite 1138d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org data = self.data 1139d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org i = 10 1140d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org components = [] 1141d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org more = 1 1142d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org while more: 1143d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org flags, glyphID = struct.unpack(">HH", data[i:i+4]) 1144d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org i += 4 1145d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org flags = int(flags) 1146d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org components.append(glyfTable.getGlyphName(int(glyphID))) 1147d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org 1148d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org if flags & 0x0001: i += 4 # ARG_1_AND_2_ARE_WORDS 1149d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org else: i += 2 1150d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org if flags & 0x0008: i += 2 # WE_HAVE_A_SCALE 1151d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org elif flags & 0x0040: i += 4 # WE_HAVE_AN_X_AND_Y_SCALE 1152d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org elif flags & 0x0080: i += 8 # WE_HAVE_A_TWO_BY_TWO 1153d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org more = flags & 0x0020 # MORE_COMPONENTS 1154d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org 1155d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org return components 1156d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org 1157d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org@_add_method(fontTools.ttLib.getTableModule('glyf').Glyph) 1158d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.orgdef remapComponentsFast(self, indices): 1159d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org if not self.data or struct.unpack(">h", self.data[:2])[0] >= 0: 1160d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org return # Not composite 1161d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org data = array.array("B", self.data) 1162d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org i = 10 1163d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org more = 1 1164d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org while more: 1165d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org flags =(data[i] << 8) | data[i+1] 1166d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org glyphID =(data[i+2] << 8) | data[i+3] 1167d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org # Remap 1168d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org glyphID = indices.index(glyphID) 1169d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org data[i+2] = glyphID >> 8 1170a4e13c85b23fe7530ae89a84ef671ebd5e451e80bsalomon@google.com data[i+3] = glyphID & 0xFF 117151a6286c241c1dc750d263ed9676079c898148b0bsalomon@google.com i += 4 1172e4fafb146e85cdfcf9d5418597b6818aa0754adatfarina@chromium.org flags = int(flags) 1173bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.com 1174bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.com if flags & 0x0001: i += 4 # ARG_1_AND_2_ARE_WORDS 117580214e26c57c5fea954006400852e8999e201923robertphillips@google.com else: i += 2 1176bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.com if flags & 0x0008: i += 2 # WE_HAVE_A_SCALE 1177bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.com elif flags & 0x0040: i += 4 # WE_HAVE_AN_X_AND_Y_SCALE 1178bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.com elif flags & 0x0080: i += 8 # WE_HAVE_A_TWO_BY_TWO 1179bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.com more = flags & 0x0020 # MORE_COMPONENTS 1180bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.com 1181bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.com self.data = data.tostring() 1182bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.com 1183bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.com@_add_method(fontTools.ttLib.getTableModule('glyf').Glyph) 1184bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.comdef dropInstructionsFast(self): 1185d9f2dea5328c9ab455852f2e4928cca7c71c6b05reed@google.com if not self.data: 1186bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.com return 1187bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.com numContours = struct.unpack(">h", self.data[:2])[0] 1188bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.com data = array.array("B", self.data) 118980214e26c57c5fea954006400852e8999e201923robertphillips@google.com i = 10 11908182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com if numContours >= 0: 11912047f00e4698f83499ab91911999a65c21a951c9epoger@google.com i += 2 * numContours # endPtsOfContours 11922047f00e4698f83499ab91911999a65c21a951c9epoger@google.com instructionLen =(data[i] << 8) | data[i+1] 1193bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.com # Zero it 119449f085dddff10473b6ebf832a974288300224e60bsalomon data[i] = data [i+1] = 0 11958182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com i += 2 11968182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com if instructionLen: 11978182fa0cac76e7e6d583aebba060229230516887bsalomon@google.com # Splice it out 1198bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.com data = data[:i] + data[i+instructionLen:] 1199bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.com else: 1200bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.com more = 1 1201bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.com while more: 120280214e26c57c5fea954006400852e8999e201923robertphillips@google.com flags =(data[i] << 8) | data[i+1] 1203bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.com # Turn instruction flag off 12041e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org flags &= ~0x0100 # WE_HAVE_INSTRUCTIONS 12051e1c36f4f89ad39e1d248edb745919e493242c68vandebo@chromium.org data[i+0] = flags >> 8 120680214e26c57c5fea954006400852e8999e201923robertphillips@google.com data[i+1] = flags & 0xFF 1207e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org i += 4 1208e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org flags = int(flags) 1209e5b2af955b7d06815ddd405659ad62a2a8355ca3commit-bot@chromium.org 1210cc6493bbef7c9c2adf4b1ed8701e2ed015ae745drobertphillips@google.com if flags & 0x0001: i += 4 # ARG_1_AND_2_ARE_WORDS 121108eacc144711cd5d33513b2fba7a635ad28b7208robertphillips@google.com else: i += 2 12126fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org if flags & 0x0008: i += 2 # WE_HAVE_A_SCALE 1213edf32d5b0e7694833287024e03da38521a0adf05junov@chromium.org elif flags & 0x0040: i += 4 # WE_HAVE_AN_X_AND_Y_SCALE 12146fbe54c663bd0eed6f6519c31a4c8e291db2613bcommit-bot@chromium.org elif flags & 0x0080: i += 8 # WE_HAVE_A_TWO_BY_TWO 12158cdf0f52ff395d4053f7ed5c20861c42eba25d31junov@chromium.org more = flags & 0x0020 # MORE_COMPONENTS 1216e7b3d29a1289e64130dd0ec905d94feedc9d1064bsalomon@google.com 1217edb26fdb8349a727b226e90cbeab06cd25f5cac0bsalomon@google.com # Cut off 1218d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org data = data[:i] 1219d3e5842db0cb169e10d6da1e62c94ba5cf182bb4commit-bot@chromium.org if len(data) % 4: 1220e7b3d29a1289e64130dd0ec905d94feedc9d1064bsalomon@google.com # add pad bytes 1221bdee9fc778d4387d805d717f2cd7fc7074991fdbreed@google.com nPadBytes = 4 -(len(data) % 4) 1222 for i in range(nPadBytes): 1223 data.append(0) 1224 self.data = data.tostring() 1225 1226@_add_method(fontTools.ttLib.getTableClass('glyf')) 1227def closure_glyphs(self, s): 1228 decompose = s.glyphs 1229 # I don't know if component glyphs can be composite themselves. 1230 # We handle them anyway. 1231 while True: 1232 components = set() 1233 for g in decompose: 1234 if g not in self.glyphs: 1235 continue 1236 gl = self.glyphs[g] 1237 if hasattr(gl, "data"): 1238 for c in gl.getComponentNamesFast(self): 1239 if c not in s.glyphs: 1240 components.add(c) 1241 else: 1242 # TTX seems to expand gid0..3 always 1243 if gl.isComposite(): 1244 for c in gl.components: 1245 if c.glyphName not in s.glyphs: 1246 components.add(c.glyphName) 1247 components = set(c for c in components if c not in s.glyphs) 1248 if not components: 1249 break 1250 decompose = components 1251 s.glyphs.update(components) 1252 1253@_add_method(fontTools.ttLib.getTableClass('glyf')) 1254def prune_pre_subset(self, options): 1255 if options.notdef_glyph and not options.notdef_outline: 1256 g = self[self.glyphOrder[0]] 1257 # Yay, easy! 1258 g.__dict__.clear() 1259 g.data = "" 1260 return True 1261 1262@_add_method(fontTools.ttLib.getTableClass('glyf')) 1263def subset_glyphs(self, s): 1264 self.glyphs = dict((g,v) for g,v in self.glyphs.iteritems() if g in s.glyphs) 1265 indices = [i for i,g in enumerate(self.glyphOrder) if g in s.glyphs] 1266 for v in self.glyphs.itervalues(): 1267 if hasattr(v, "data"): 1268 v.remapComponentsFast(indices) 1269 else: 1270 pass # No need 1271 self.glyphOrder = [g for g in self.glyphOrder if g in s.glyphs] 1272 # Don't drop empty 'glyf' tables, otherwise 'loca' doesn't get subset. 1273 return True 1274 1275@_add_method(fontTools.ttLib.getTableClass('glyf')) 1276def prune_post_subset(self, options): 1277 if not options.hinting: 1278 for v in self.glyphs.itervalues(): 1279 if hasattr(v, "data"): 1280 v.dropInstructionsFast() 1281 else: 1282 v.program = fontTools.ttLib.tables.ttProgram.Program() 1283 v.program.fromBytecode([]) 1284 return True 1285 1286@_add_method(fontTools.ttLib.getTableClass('CFF ')) 1287def prune_pre_subset(self, options): 1288 cff = self.cff 1289 # CFF table should have one font only 1290 cff.fontNames = cff.fontNames[:1] 1291 1292 if options.notdef_glyph and not options.notdef_outline: 1293 for fontname in cff.keys(): 1294 font = cff[fontname] 1295 c,_ = font.CharStrings.getItemAndSelector('.notdef') 1296 c.bytecode = '\x0e' # endchar 1297 c.program = None 1298 1299 return True # bool(cff.fontNames) 1300 1301@_add_method(fontTools.ttLib.getTableClass('CFF ')) 1302def subset_glyphs(self, s): 1303 cff = self.cff 1304 for fontname in cff.keys(): 1305 font = cff[fontname] 1306 cs = font.CharStrings 1307 1308 # Load all glyphs 1309 for g in font.charset: 1310 if g not in s.glyphs: continue 1311 c,sel = cs.getItemAndSelector(g) 1312 1313 if cs.charStringsAreIndexed: 1314 indices = [i for i,g in enumerate(font.charset) if g in s.glyphs] 1315 csi = cs.charStringsIndex 1316 csi.items = [csi.items[i] for i in indices] 1317 csi.count = len(csi.items) 1318 del csi.file, csi.offsets 1319 if hasattr(font, "FDSelect"): 1320 sel = font.FDSelect 1321 sel.format = None 1322 sel.gidArray = [sel.gidArray[i] for i in indices] 1323 cs.charStrings = dict((g,indices.index(v)) 1324 for g,v in cs.charStrings.iteritems() 1325 if g in s.glyphs) 1326 else: 1327 cs.charStrings = dict((g,v) 1328 for g,v in cs.charStrings.iteritems() 1329 if g in s.glyphs) 1330 font.charset = [g for g in font.charset if g in s.glyphs] 1331 font.numGlyphs = len(font.charset) 1332 1333 return True # any(cff[fontname].numGlyphs for fontname in cff.keys()) 1334 1335@_add_method(fontTools.misc.psCharStrings.T2CharString) 1336def subset_subroutines(self, subrs, gsubrs): 1337 p = self.program 1338 for i in xrange(1, len(p)): 1339 if p[i] == 'callsubr': 1340 assert type(p[i-1]) is int 1341 p[i-1] = subrs._used.index(p[i-1] + subrs._old_bias) - subrs._new_bias 1342 elif p[i] == 'callgsubr': 1343 assert type(p[i-1]) is int 1344 p[i-1] = gsubrs._used.index(p[i-1] + gsubrs._old_bias) - gsubrs._new_bias 1345 1346@_add_method(fontTools.ttLib.getTableClass('CFF ')) 1347def prune_post_subset(self, options): 1348 cff = self.cff 1349 1350 class _MarkingT2Decompiler(fontTools.misc.psCharStrings.SimpleT2Decompiler): 1351 1352 def __init__(self, localSubrs, globalSubrs): 1353 fontTools.misc.psCharStrings.SimpleT2Decompiler.__init__(self, 1354 localSubrs, 1355 globalSubrs) 1356 for subrs in [localSubrs, globalSubrs]: 1357 if subrs and not hasattr(subrs, "_used"): 1358 subrs._used = set() 1359 1360 def op_callsubr(self, index): 1361 self.localSubrs._used.add(self.operandStack[-1]+self.localBias) 1362 fontTools.misc.psCharStrings.SimpleT2Decompiler.op_callsubr(self, index) 1363 1364 def op_callgsubr(self, index): 1365 self.globalSubrs._used.add(self.operandStack[-1]+self.globalBias) 1366 fontTools.misc.psCharStrings.SimpleT2Decompiler.op_callgsubr(self, index) 1367 1368 class _NonrecursingT2Decompiler(fontTools.misc.psCharStrings.SimpleT2Decompiler): 1369 1370 def __init__(self, localSubrs, globalSubrs): 1371 fontTools.misc.psCharStrings.SimpleT2Decompiler.__init__(self, 1372 localSubrs, 1373 globalSubrs) 1374 1375 def op_callsubr(self, index): 1376 self.pop() 1377 1378 def op_callgsubr(self, index): 1379 self.pop() 1380 1381 for fontname in cff.keys(): 1382 font = cff[fontname] 1383 cs = font.CharStrings 1384 1385 # Drop unused FontDictionaries 1386 if hasattr(font, "FDSelect"): 1387 sel = font.FDSelect 1388 indices = _uniq_sort(sel.gidArray) 1389 sel.gidArray = [indices.index (ss) for ss in sel.gidArray] 1390 arr = font.FDArray 1391 arr.items = [arr[i] for i in indices] 1392 arr.count = len(arr.items) 1393 del arr.file, arr.offsets 1394 1395 # Mark all used subroutines 1396 for g in font.charset: 1397 c,sel = cs.getItemAndSelector(g) 1398 subrs = getattr(c.private, "Subrs", []) 1399 decompiler = _MarkingT2Decompiler(subrs, c.globalSubrs) 1400 decompiler.execute(c) 1401 1402 # Renumber subroutines to remove unused ones 1403 all_subrs = [font.GlobalSubrs] 1404 if hasattr(font, 'FDSelect'): 1405 all_subrs.extend(fd.Private.Subrs for fd in font.FDArray if hasattr(fd.Private, 'Subrs')) 1406 elif hasattr(font.Private, 'Subrs'): 1407 all_subrs.append(font.Private.Subrs) 1408 # Prepare 1409 for subrs in all_subrs: 1410 if not subrs: continue 1411 if not hasattr(subrs, '_used'): 1412 subrs._used = set() 1413 subrs._used = _uniq_sort(subrs._used) 1414 subrs._old_bias = fontTools.misc.psCharStrings.calcSubrBias(subrs) 1415 subrs._new_bias = fontTools.misc.psCharStrings.calcSubrBias(subrs._used) 1416 # Renumber glyph charstrings 1417 for g in font.charset: 1418 c,sel = cs.getItemAndSelector(g) 1419 subrs = getattr(c.private, "Subrs", []) 1420 c.subset_subroutines (subrs, font.GlobalSubrs) 1421 # Renumber subroutines themselves 1422 for subrs in all_subrs: 1423 if not subrs: continue 1424 decompiler = _NonrecursingT2Decompiler(subrs, font.GlobalSubrs) 1425 for i in xrange (subrs.count): 1426 if i not in subrs._used: continue 1427 decompiler.reset() 1428 decompiler.execute(subrs[i]) 1429 if subrs == font.GlobalSubrs: 1430 if not hasattr(font, 'FDSelect') and hasattr(font.Private, 'Subrs'): 1431 local_subrs = font.Private.Subrs 1432 else: 1433 local_subrs = [] 1434 else: 1435 local_subrs = subrs 1436 subrs[i].subset_subroutines (local_subrs, font.GlobalSubrs) 1437 # Cleanup 1438 for subrs in all_subrs: 1439 if not subrs: continue 1440 subrs.items = [subrs.items[i] for i in subrs._used] 1441 del subrs.file, subrs.offsets 1442 del subrs._used, subrs._old_bias, subrs._new_bias 1443 1444 if not options.hinting: 1445 pass # TODO(behdad) Drop hints 1446 1447 return True 1448 1449@_add_method(fontTools.ttLib.getTableClass('cmap')) 1450def closure_glyphs(self, s): 1451 tables = [t for t in self.tables 1452 if t.platformID == 3 and t.platEncID in [1, 10]] 1453 for u in s.unicodes_requested: 1454 found = False 1455 for table in tables: 1456 if u in table.cmap: 1457 s.glyphs.add(table.cmap[u]) 1458 found = True 1459 break 1460 if not found: 1461 s.log("No glyph for Unicode value %s; skipping." % u) 1462 1463@_add_method(fontTools.ttLib.getTableClass('cmap')) 1464def prune_pre_subset(self, options): 1465 if not options.legacy_cmap: 1466 # Drop non-Unicode / non-Symbol cmaps 1467 self.tables = [t for t in self.tables 1468 if t.platformID == 3 and t.platEncID in [0, 1, 10]] 1469 if not options.symbol_cmap: 1470 self.tables = [t for t in self.tables 1471 if t.platformID == 3 and t.platEncID in [1, 10]] 1472 # TODO(behdad) Only keep one subtable? 1473 # For now, drop format=0 which can't be subset_glyphs easily? 1474 self.tables = [t for t in self.tables if t.format != 0] 1475 return bool(self.tables) 1476 1477@_add_method(fontTools.ttLib.getTableClass('cmap')) 1478def subset_glyphs(self, s): 1479 s.glyphs = s.glyphs_cmaped 1480 for t in self.tables: 1481 # For reasons I don't understand I need this here 1482 # to force decompilation of the cmap format 14. 1483 try: 1484 getattr(t, "asdf") 1485 except AttributeError: 1486 pass 1487 if t.format == 14: 1488 # TODO(behdad) XXX We drop all the default-UVS mappings(g==None). 1489 t.uvsDict = dict((v,[(u,g) for u,g in l if g in s.glyphs]) 1490 for v,l in t.uvsDict.iteritems()) 1491 t.uvsDict = dict((v,l) for v,l in t.uvsDict.iteritems() if l) 1492 else: 1493 t.cmap = dict((u,g) for u,g in t.cmap.iteritems() 1494 if g in s.glyphs_requested or u in s.unicodes_requested) 1495 self.tables = [t for t in self.tables 1496 if (t.cmap if t.format != 14 else t.uvsDict)] 1497 # TODO(behdad) Convert formats when needed. 1498 # In particular, if we have a format=12 without non-BMP 1499 # characters, either drop format=12 one or convert it 1500 # to format=4 if there's not one. 1501 return bool(self.tables) 1502 1503@_add_method(fontTools.ttLib.getTableClass('name')) 1504def prune_pre_subset(self, options): 1505 if '*' not in options.name_IDs: 1506 self.names = [n for n in self.names if n.nameID in options.name_IDs] 1507 if not options.name_legacy: 1508 self.names = [n for n in self.names 1509 if n.platformID == 3 and n.platEncID == 1] 1510 if '*' not in options.name_languages: 1511 self.names = [n for n in self.names if n.langID in options.name_languages] 1512 return True # Retain even if empty 1513 1514 1515# TODO(behdad) OS/2 ulUnicodeRange / ulCodePageRange? 1516# TODO(behdad) Drop unneeded GSUB/GPOS Script/LangSys entries. 1517# TODO(behdad) Drop empty GSUB/GPOS, and GDEF if no GSUB/GPOS left 1518# TODO(behdad) Drop GDEF subitems if unused by lookups 1519# TODO(behdad) Avoid recursing too much (in GSUB/GPOS and in CFF) 1520# TODO(behdad) Text direction considerations. 1521# TODO(behdad) Text script / language considerations. 1522 1523 1524class Options(object): 1525 1526 class UnknownOptionError(Exception): 1527 pass 1528 1529 _drop_tables_default = ['BASE', 'JSTF', 'DSIG', 'EBDT', 'EBLC', 'EBSC', 'SVG ', 1530 'PCLT', 'LTSH'] 1531 _drop_tables_default += ['Feat', 'Glat', 'Gloc', 'Silf', 'Sill'] # Graphite 1532 _drop_tables_default += ['CBLC', 'CBDT', 'sbix', 'COLR', 'CPAL'] # Color 1533 _no_subset_tables_default = ['gasp', 'head', 'hhea', 'maxp', 'vhea', 'OS/2', 1534 'loca', 'name', 'cvt ', 'fpgm', 'prep'] 1535 _hinting_tables_default = ['cvt ', 'fpgm', 'prep', 'hdmx', 'VDMX'] 1536 1537 # Based on HarfBuzz shapers 1538 _layout_features_groups = { 1539 # Default shaper 1540 'common': ['ccmp', 'liga', 'locl', 'mark', 'mkmk', 'rlig'], 1541 'horizontal': ['calt', 'clig', 'curs', 'kern', 'rclt'], 1542 'vertical': ['valt', 'vert', 'vkrn', 'vpal', 'vrt2'], 1543 'ltr': ['ltra', 'ltrm'], 1544 'rtl': ['rtla', 'rtlm'], 1545 # Complex shapers 1546 'arabic': ['init', 'medi', 'fina', 'isol', 'med2', 'fin2', 'fin3', 1547 'cswh', 'mset'], 1548 'hangul': ['ljmo', 'vjmo', 'tjmo'], 1549 'tibetal': ['abvs', 'blws', 'abvm', 'blwm'], 1550 'indic': ['nukt', 'akhn', 'rphf', 'rkrf', 'pref', 'blwf', 'half', 1551 'abvf', 'pstf', 'cfar', 'vatu', 'cjct', 'init', 'pres', 1552 'abvs', 'blws', 'psts', 'haln', 'dist', 'abvm', 'blwm'], 1553 } 1554 _layout_features_default = _uniq_sort(sum( 1555 _layout_features_groups.itervalues(), [])) 1556 1557 drop_tables = _drop_tables_default 1558 no_subset_tables = _no_subset_tables_default 1559 hinting_tables = _hinting_tables_default 1560 layout_features = _layout_features_default 1561 hinting = False 1562 glyph_names = False 1563 legacy_cmap = False 1564 symbol_cmap = False 1565 name_IDs = [1, 2] # Family and Style 1566 name_legacy = False 1567 name_languages = [0x0409] # English 1568 notdef_glyph = True # gid0 for TrueType / .notdef for CFF 1569 notdef_outline = False # No need for notdef to have an outline really 1570 recommended_glyphs = False # gid1, gid2, gid3 for TrueType 1571 recalc_bounds = False # Recalculate font bounding boxes 1572 canonical_order = False # Order tables as recommended 1573 flavor = None # May be 'woff' 1574 1575 def __init__(self, **kwargs): 1576 1577 self.set(**kwargs) 1578 1579 def set(self, **kwargs): 1580 for k,v in kwargs.iteritems(): 1581 if not hasattr(self, k): 1582 raise self.UnknownOptionError("Unknown option '%s'" % a) 1583 setattr(self, k, v) 1584 1585 def parse_opts(self, argv, ignore_unknown=False): 1586 ret = [] 1587 opts = {} 1588 for a in argv: 1589 orig_a = a 1590 if not a.startswith('--'): 1591 ret.append(a) 1592 continue 1593 a = a[2:] 1594 i = a.find('=') 1595 op = '=' 1596 if i == -1: 1597 if a.startswith("no-"): 1598 k = a[3:] 1599 v = False 1600 else: 1601 k = a 1602 v = True 1603 else: 1604 k = a[:i] 1605 if k[-1] in "-+": 1606 op = k[-1]+'=' # Ops is '-=' or '+=' now. 1607 k = k[:-1] 1608 v = a[i+1:] 1609 k = k.replace('-', '_') 1610 if not hasattr(self, k): 1611 if ignore_unknown == True or k in ignore_unknown: 1612 ret.append(orig_a) 1613 continue 1614 else: 1615 raise self.UnknownOptionError("Unknown option '%s'" % a) 1616 1617 ov = getattr(self, k) 1618 if isinstance(ov, bool): 1619 v = bool(v) 1620 elif isinstance(ov, int): 1621 v = int(v) 1622 elif isinstance(ov, list): 1623 vv = v.split(',') 1624 if vv == ['']: 1625 vv = [] 1626 vv = [int(x, 0) if len(x) and x[0] in "0123456789" else x for x in vv] 1627 if op == '=': 1628 v = vv 1629 elif op == '+=': 1630 v = ov 1631 v.extend(vv) 1632 elif op == '-=': 1633 v = ov 1634 for x in vv: 1635 if x in v: 1636 v.remove(x) 1637 else: 1638 assert 0 1639 1640 opts[k] = v 1641 self.set(**opts) 1642 1643 return ret 1644 1645 1646class Subsetter(object): 1647 1648 def __init__(self, options=None, log=None): 1649 1650 if not log: 1651 log = Logger() 1652 if not options: 1653 options = Options() 1654 1655 self.options = options 1656 self.log = log 1657 self.unicodes_requested = set() 1658 self.glyphs_requested = set() 1659 self.glyphs = set() 1660 1661 def populate(self, glyphs=[], unicodes=[], text=""): 1662 self.unicodes_requested.update(unicodes) 1663 if isinstance(text, str): 1664 text = text.decode("utf8") 1665 for u in text: 1666 self.unicodes_requested.add(ord(u)) 1667 self.glyphs_requested.update(glyphs) 1668 self.glyphs.update(glyphs) 1669 1670 def _prune_pre_subset(self, font): 1671 1672 for tag in font.keys(): 1673 if tag == 'GlyphOrder': continue 1674 1675 if(tag in self.options.drop_tables or 1676 (tag in self.options.hinting_tables and not self.options.hinting)): 1677 self.log(tag, "dropped") 1678 del font[tag] 1679 continue 1680 1681 clazz = fontTools.ttLib.getTableClass(tag) 1682 1683 if hasattr(clazz, 'prune_pre_subset'): 1684 table = font[tag] 1685 retain = table.prune_pre_subset(self.options) 1686 self.log.lapse("prune '%s'" % tag) 1687 if not retain: 1688 self.log(tag, "pruned to empty; dropped") 1689 del font[tag] 1690 continue 1691 else: 1692 self.log(tag, "pruned") 1693 1694 def _closure_glyphs(self, font): 1695 1696 self.glyphs = self.glyphs_requested.copy() 1697 1698 if 'cmap' in font: 1699 font['cmap'].closure_glyphs(self) 1700 self.glyphs_cmaped = self.glyphs 1701 1702 if self.options.notdef_glyph: 1703 if 'glyf' in font: 1704 self.glyphs.add(font.getGlyphName(0)) 1705 self.log("Added gid0 to subset") 1706 else: 1707 self.glyphs.add('.notdef') 1708 self.log("Added .notdef to subset") 1709 if self.options.recommended_glyphs: 1710 if 'glyf' in font: 1711 for i in range(4): 1712 self.glyphs.add(font.getGlyphName(i)) 1713 self.log("Added first four glyphs to subset") 1714 1715 if 'GSUB' in font: 1716 self.log("Closing glyph list over 'GSUB': %d glyphs before" % 1717 len(self.glyphs)) 1718 self.log.glyphs(self.glyphs, font=font) 1719 font['GSUB'].closure_glyphs(self) 1720 self.log("Closed glyph list over 'GSUB': %d glyphs after" % 1721 len(self.glyphs)) 1722 self.log.glyphs(self.glyphs, font=font) 1723 self.log.lapse("close glyph list over 'GSUB'") 1724 self.glyphs_gsubed = self.glyphs.copy() 1725 1726 if 'glyf' in font: 1727 self.log("Closing glyph list over 'glyf': %d glyphs before" % 1728 len(self.glyphs)) 1729 self.log.glyphs(self.glyphs, font=font) 1730 font['glyf'].closure_glyphs(self) 1731 self.log("Closed glyph list over 'glyf': %d glyphs after" % 1732 len(self.glyphs)) 1733 self.log.glyphs(self.glyphs, font=font) 1734 self.log.lapse("close glyph list over 'glyf'") 1735 self.glyphs_glyfed = self.glyphs.copy() 1736 1737 self.glyphs_all = self.glyphs.copy() 1738 1739 self.log("Retaining %d glyphs: " % len(self.glyphs_all)) 1740 1741 def _subset_glyphs(self, font): 1742 for tag in font.keys(): 1743 if tag == 'GlyphOrder': continue 1744 clazz = fontTools.ttLib.getTableClass(tag) 1745 1746 if tag in self.options.no_subset_tables: 1747 self.log(tag, "subsetting not needed") 1748 elif hasattr(clazz, 'subset_glyphs'): 1749 table = font[tag] 1750 self.glyphs = self.glyphs_all 1751 retain = table.subset_glyphs(self) 1752 self.glyphs = self.glyphs_all 1753 self.log.lapse("subset '%s'" % tag) 1754 if not retain: 1755 self.log(tag, "subsetted to empty; dropped") 1756 del font[tag] 1757 else: 1758 self.log(tag, "subsetted") 1759 else: 1760 self.log(tag, "NOT subset; don't know how to subset; dropped") 1761 del font[tag] 1762 1763 glyphOrder = font.getGlyphOrder() 1764 glyphOrder = [g for g in glyphOrder if g in self.glyphs_all] 1765 font.setGlyphOrder(glyphOrder) 1766 font._buildReverseGlyphOrderDict() 1767 self.log.lapse("subset GlyphOrder") 1768 1769 def _prune_post_subset(self, font): 1770 for tag in font.keys(): 1771 if tag == 'GlyphOrder': continue 1772 clazz = fontTools.ttLib.getTableClass(tag) 1773 if hasattr(clazz, 'prune_post_subset'): 1774 table = font[tag] 1775 retain = table.prune_post_subset(self.options) 1776 self.log.lapse("prune '%s'" % tag) 1777 if not retain: 1778 self.log(tag, "pruned to empty; dropped") 1779 del font[tag] 1780 else: 1781 self.log(tag, "pruned") 1782 1783 def subset(self, font): 1784 1785 self._prune_pre_subset(font) 1786 self._closure_glyphs(font) 1787 self._subset_glyphs(font) 1788 self._prune_post_subset(font) 1789 1790 1791class Logger(object): 1792 1793 def __init__(self, verbose=False, xml=False, timing=False): 1794 self.verbose = verbose 1795 self.xml = xml 1796 self.timing = timing 1797 self.last_time = self.start_time = time.time() 1798 1799 def parse_opts(self, argv): 1800 argv = argv[:] 1801 for v in ['verbose', 'xml', 'timing']: 1802 if "--"+v in argv: 1803 setattr(self, v, True) 1804 argv.remove("--"+v) 1805 return argv 1806 1807 def __call__(self, *things): 1808 if not self.verbose: 1809 return 1810 print ' '.join(str(x) for x in things) 1811 1812 def lapse(self, *things): 1813 if not self.timing: 1814 return 1815 new_time = time.time() 1816 print "Took %0.3fs to %s" %(new_time - self.last_time, 1817 ' '.join(str(x) for x in things)) 1818 self.last_time = new_time 1819 1820 def glyphs(self, glyphs, font=None): 1821 self("Names: ", sorted(glyphs)) 1822 if font: 1823 reverseGlyphMap = font.getReverseGlyphMap() 1824 self("Gids : ", sorted(reverseGlyphMap[g] for g in glyphs)) 1825 1826 def font(self, font, file=sys.stdout): 1827 if not self.xml: 1828 return 1829 import xmlWriter 1830 writer = xmlWriter.XMLWriter(file) 1831 font.disassembleInstructions = False # Work around ttLib bug 1832 for tag in font.keys(): 1833 writer.begintag(tag) 1834 writer.newline() 1835 font[tag].toXML(writer, font) 1836 writer.endtag(tag) 1837 writer.newline() 1838 1839 1840def load_font(fontFile, 1841 options, 1842 checkChecksums=False, 1843 dontLoadGlyphNames=False): 1844 1845 font = fontTools.ttLib.TTFont(fontFile, 1846 checkChecksums=checkChecksums, 1847 recalcBBoxes=options.recalc_bounds) 1848 1849 # Hack: 1850 # 1851 # If we don't need glyph names, change 'post' class to not try to 1852 # load them. It avoid lots of headache with broken fonts as well 1853 # as loading time. 1854 # 1855 # Ideally ttLib should provide a way to ask it to skip loading 1856 # glyph names. But it currently doesn't provide such a thing. 1857 # 1858 if dontLoadGlyphNames: 1859 post = fontTools.ttLib.getTableClass('post') 1860 saved = post.decode_format_2_0 1861 post.decode_format_2_0 = post.decode_format_3_0 1862 f = font['post'] 1863 if f.formatType == 2.0: 1864 f.formatType = 3.0 1865 post.decode_format_2_0 = saved 1866 1867 return font 1868 1869def save_font(font, outfile, options): 1870 if options.flavor and not hasattr(font, 'flavor'): 1871 raise Exception("fonttools version does not support flavors.") 1872 font.flavor = options.flavor 1873 font.save(outfile, reorderTables=options.canonical_order) 1874 1875def main(args): 1876 1877 log = Logger() 1878 args = log.parse_opts(args) 1879 1880 options = Options() 1881 args = options.parse_opts(args, ignore_unknown=['text']) 1882 1883 if len(args) < 2: 1884 print >>sys.stderr, "usage: pyftsubset font-file glyph... [--text=ABC]... [--option=value]..." 1885 sys.exit(1) 1886 1887 fontfile = args[0] 1888 args = args[1:] 1889 1890 dontLoadGlyphNames =(not options.glyph_names and 1891 all(any(g.startswith(p) 1892 for p in ['gid', 'glyph', 'uni', 'U+']) 1893 for g in args)) 1894 1895 font = load_font(fontfile, options, dontLoadGlyphNames=dontLoadGlyphNames) 1896 subsetter = Subsetter(options=options, log=log) 1897 log.lapse("load font") 1898 1899 names = font.getGlyphNames() 1900 log.lapse("loading glyph names") 1901 1902 glyphs = [] 1903 unicodes = [] 1904 text = "" 1905 for g in args: 1906 if g in names: 1907 glyphs.append(g) 1908 continue 1909 if g.startswith('--text='): 1910 text += g[7:] 1911 continue 1912 if g.startswith('uni') or g.startswith('U+'): 1913 if g.startswith('uni') and len(g) > 3: 1914 g = g[3:] 1915 elif g.startswith('U+') and len(g) > 2: 1916 g = g[2:] 1917 u = int(g, 16) 1918 unicodes.append(u) 1919 continue 1920 if g.startswith('gid') or g.startswith('glyph'): 1921 if g.startswith('gid') and len(g) > 3: 1922 g = g[3:] 1923 elif g.startswith('glyph') and len(g) > 5: 1924 g = g[5:] 1925 try: 1926 glyphs.append(font.getGlyphName(int(g), requireReal=1)) 1927 except ValueError: 1928 raise Exception("Invalid glyph identifier: %s" % g) 1929 continue 1930 raise Exception("Invalid glyph identifier: %s" % g) 1931 log.lapse("compile glyph list") 1932 log("Unicodes:", unicodes) 1933 log("Glyphs:", glyphs) 1934 1935 subsetter.populate(glyphs=glyphs, unicodes=unicodes, text=text) 1936 subsetter.subset(font) 1937 1938 outfile = fontfile + '.subset' 1939 1940 save_font (font, outfile, options) 1941 log.lapse("compile and save font") 1942 1943 log.last_time = log.start_time 1944 log.lapse("make one with everything(TOTAL TIME)") 1945 1946 if log.verbose: 1947 import os 1948 log("Input font: %d bytes" % os.path.getsize(fontfile)) 1949 log("Subset font: %d bytes" % os.path.getsize(outfile)) 1950 1951 log.font(font) 1952 1953 font.close() 1954 1955 1956__all__ = [ 1957 'Options', 1958 'Subsetter', 1959 'Logger', 1960 'load_font', 1961 'save_font', 1962 'main' 1963] 1964 1965if __name__ == '__main__': 1966 main(sys.argv[1:]) 1967