Behdad Esfahbod | 5466061 | 2013-07-21 18:16:55 -0400 | [diff] [blame] | 1 | #!/usr/bin/python |
| 2 | |
| 3 | # Python OpenType Layout Subsetter |
Behdad Esfahbod | 4aa6ce3 | 2013-07-22 12:15:36 -0400 | [diff] [blame^] | 4 | # Written by: Behdad Esfahbod |
Behdad Esfahbod | 5466061 | 2013-07-21 18:16:55 -0400 | [diff] [blame] | 5 | |
| 6 | import fontTools.ttx |
Behdad Esfahbod | 5466061 | 2013-07-21 18:16:55 -0400 | [diff] [blame] | 7 | |
Behdad Esfahbod | 5466061 | 2013-07-21 18:16:55 -0400 | [diff] [blame] | 8 | |
Behdad Esfahbod | 02b9206 | 2013-07-21 18:40:59 -0400 | [diff] [blame] | 9 | def add_method (*clazzes): |
Behdad Esfahbod | 5466061 | 2013-07-21 18:16:55 -0400 | [diff] [blame] | 10 | def wrapper(method): |
Behdad Esfahbod | 02b9206 | 2013-07-21 18:40:59 -0400 | [diff] [blame] | 11 | for clazz in clazzes: |
| 12 | setattr (clazz, method.func_name, method) |
Behdad Esfahbod | 5466061 | 2013-07-21 18:16:55 -0400 | [diff] [blame] | 13 | return wrapper |
| 14 | |
Behdad Esfahbod | 5466061 | 2013-07-21 18:16:55 -0400 | [diff] [blame] | 15 | # Subset |
Behdad Esfahbod | 5466061 | 2013-07-21 18:16:55 -0400 | [diff] [blame] | 16 | |
| 17 | @add_method(fontTools.ttLib.tables.otTables.Coverage) |
| 18 | def subset (self, glyphs): |
| 19 | indices = [i for (i,g) in enumerate (self.glyphs) if g in glyphs] |
| 20 | self.glyphs = [g for g in self.glyphs if g in glyphs] |
| 21 | return indices |
Behdad Esfahbod | d1d41bc | 2013-07-21 23:15:32 -0400 | [diff] [blame] | 22 | |
| 23 | @add_method(fontTools.ttLib.tables.otTables.Coverage) |
| 24 | def __nonzero__ (self): |
| 25 | return bool (self.glyphs) |
Behdad Esfahbod | 5466061 | 2013-07-21 18:16:55 -0400 | [diff] [blame] | 26 | |
| 27 | @add_method(fontTools.ttLib.tables.otTables.ClassDef) |
| 28 | def subset (self, glyphs): |
Behdad Esfahbod | 4aa6ce3 | 2013-07-22 12:15:36 -0400 | [diff] [blame^] | 29 | "Returns ascending list of remaining classes." |
Behdad Esfahbod | 5466061 | 2013-07-21 18:16:55 -0400 | [diff] [blame] | 30 | self.classDefs = {g:v for g,v in self.classDefs.items() if g in glyphs} |
Behdad Esfahbod | 4aa6ce3 | 2013-07-22 12:15:36 -0400 | [diff] [blame^] | 31 | return {v:1 for v in self.classDefs.values ()}.keys () |
| 32 | |
| 33 | @add_method(fontTools.ttLib.tables.otTables.ClassDef) |
| 34 | def remap (self, class_map): |
| 35 | "Remaps classes." |
| 36 | self.classDefs = {g:class_map.index (v) for g,v in self.classDefs.items()} |
Behdad Esfahbod | d1d41bc | 2013-07-21 23:15:32 -0400 | [diff] [blame] | 37 | |
| 38 | @add_method(fontTools.ttLib.tables.otTables.ClassDef) |
| 39 | def __nonzero__ (self): |
| 40 | return bool (self.classDefs) |
Behdad Esfahbod | 5466061 | 2013-07-21 18:16:55 -0400 | [diff] [blame] | 41 | |
| 42 | @add_method(fontTools.ttLib.tables.otTables.SingleSubst) |
| 43 | def subset (self, glyphs): |
| 44 | if self.Format in [1, 2]: |
| 45 | self.mapping = {g:v for g,v in self.mapping.items() if g in glyphs} |
Behdad Esfahbod | d1d41bc | 2013-07-21 23:15:32 -0400 | [diff] [blame] | 46 | return len (self.mapping) |
Behdad Esfahbod | 5466061 | 2013-07-21 18:16:55 -0400 | [diff] [blame] | 47 | else: |
| 48 | assert 0, "unknown format: %s" % self.Format |
| 49 | |
| 50 | @add_method(fontTools.ttLib.tables.otTables.MultipleSubst) |
| 51 | def subset (self, glyphs): |
| 52 | if self.Format == 1: |
| 53 | indices = self.Coverage.subset (glyphs) |
| 54 | self.Sequence = [self.Sequence[i] for i in indices] |
Behdad Esfahbod | d1d41bc | 2013-07-21 23:15:32 -0400 | [diff] [blame] | 55 | self.SequenceCount = len (self.Sequence) |
| 56 | return self.SequenceCount |
Behdad Esfahbod | 5466061 | 2013-07-21 18:16:55 -0400 | [diff] [blame] | 57 | else: |
| 58 | assert 0, "unknown format: %s" % self.Format |
| 59 | |
| 60 | @add_method(fontTools.ttLib.tables.otTables.AlternateSubst) |
| 61 | def subset (self, glyphs): |
| 62 | if self.Format == 1: |
| 63 | self.alternates = {g:v for g,v in self.alternates.items() if g in glyphs} |
Behdad Esfahbod | d1d41bc | 2013-07-21 23:15:32 -0400 | [diff] [blame] | 64 | return len (self.alternates) |
Behdad Esfahbod | 5466061 | 2013-07-21 18:16:55 -0400 | [diff] [blame] | 65 | else: |
| 66 | assert 0, "unknown format: %s" % self.Format |
| 67 | |
| 68 | @add_method(fontTools.ttLib.tables.otTables.LigatureSubst) |
| 69 | def subset (self, glyphs): |
Behdad Esfahbod | d1d41bc | 2013-07-21 23:15:32 -0400 | [diff] [blame] | 70 | if self.Format == 1: |
| 71 | self.ligatures = {g:v for g,v in self.ligatures.items() if g in glyphs} |
| 72 | self.ligatures = {g:[seq for seq in seqs if all(c in glyphs for c in seq.Component)] |
| 73 | for g,seqs in self.ligatures.items()} |
| 74 | self.ligatures = {g:v for g,v in self.ligatures.items() if v} |
| 75 | return len (self.ligatures) |
| 76 | else: |
| 77 | assert 0, "unknown format: %s" % self.Format |
Behdad Esfahbod | 5466061 | 2013-07-21 18:16:55 -0400 | [diff] [blame] | 78 | |
Behdad Esfahbod | 5466061 | 2013-07-21 18:16:55 -0400 | [diff] [blame] | 79 | @add_method(fontTools.ttLib.tables.otTables.ReverseChainSingleSubst) |
| 80 | def subset (self, glyphs): |
| 81 | if self.Format == 1: |
| 82 | indices = self.Coverage.subset (glyphs) |
| 83 | self.Substitute = [self.Substitute[i] for i in indices] |
| 84 | self.GlyphCount = len (self.Substitute) |
Behdad Esfahbod | d1d41bc | 2013-07-21 23:15:32 -0400 | [diff] [blame] | 85 | return self.GlyphCount and all (c.subset (glyphs) for c in self.LookAheadCoverage + self.BacktrackCoverage) |
Behdad Esfahbod | 5466061 | 2013-07-21 18:16:55 -0400 | [diff] [blame] | 86 | else: |
| 87 | assert 0, "unknown format: %s" % self.Format |
| 88 | |
| 89 | @add_method(fontTools.ttLib.tables.otTables.SinglePos) |
| 90 | def subset (self, glyphs): |
| 91 | if self.Format == 1: |
Behdad Esfahbod | d1d41bc | 2013-07-21 23:15:32 -0400 | [diff] [blame] | 92 | return len (self.Coverage.subset (glyphs)) |
Behdad Esfahbod | 5466061 | 2013-07-21 18:16:55 -0400 | [diff] [blame] | 93 | elif self.Format == 2: |
| 94 | indices = self.Coverage.subset (glyphs) |
| 95 | self.Value = [self.Value[i] for i in indices] |
| 96 | self.ValueCount = len (self.Value) |
Behdad Esfahbod | d1d41bc | 2013-07-21 23:15:32 -0400 | [diff] [blame] | 97 | return self.ValueCount |
Behdad Esfahbod | 5466061 | 2013-07-21 18:16:55 -0400 | [diff] [blame] | 98 | else: |
| 99 | assert 0, "unknown format: %s" % self.Format |
| 100 | |
| 101 | @add_method(fontTools.ttLib.tables.otTables.PairPos) |
| 102 | def subset (self, glyphs): |
| 103 | if self.Format == 1: |
| 104 | indices = self.Coverage.subset (glyphs) |
| 105 | self.PairSet = [self.PairSet[i] for i in indices] |
| 106 | for p in self.PairSet: |
| 107 | p.PairValueRecord = [r for r in p.PairValueRecord if r.SecondGlyph in glyphs] |
| 108 | p.PairValueCount = len (p.PairValueRecord) |
Behdad Esfahbod | d1d41bc | 2013-07-21 23:15:32 -0400 | [diff] [blame] | 109 | self.PairSet = [p for p in self.PairSet if p.PairValueCount] |
Behdad Esfahbod | 5466061 | 2013-07-21 18:16:55 -0400 | [diff] [blame] | 110 | self.PairSetCount = len (self.PairSet) |
Behdad Esfahbod | d1d41bc | 2013-07-21 23:15:32 -0400 | [diff] [blame] | 111 | return self.PairSetCount |
Behdad Esfahbod | 5466061 | 2013-07-21 18:16:55 -0400 | [diff] [blame] | 112 | elif self.Format == 2: |
| 113 | self.Coverage.subset (glyphs) |
Behdad Esfahbod | 4aa6ce3 | 2013-07-22 12:15:36 -0400 | [diff] [blame^] | 114 | class1_map = self.ClassDef1.subset (glyphs) |
| 115 | class2_map = self.ClassDef2.subset (glyphs) |
| 116 | self.ClassDef1.remap (class1_map) |
| 117 | self.ClassDef2.remap (class2_map) |
| 118 | self.Class1Record = [self.Class1Record[i] for i in class1_map] |
| 119 | for c in self.Class1Record: |
| 120 | c.Class2Record = [c.Class2Record[i] for i in class2_map] |
| 121 | self.Class1Count = len (class1_map) |
| 122 | self.Class2Count = len (class2_map) |
| 123 | return self.Coverage and self.Class1Count and self.Class2Count |
Behdad Esfahbod | 5466061 | 2013-07-21 18:16:55 -0400 | [diff] [blame] | 124 | else: |
| 125 | assert 0, "unknown format: %s" % self.Format |
| 126 | |
| 127 | @add_method(fontTools.ttLib.tables.otTables.CursivePos) |
| 128 | def subset (self, glyphs): |
| 129 | if self.Format == 1: |
| 130 | indices = self.Coverage.subset (glyphs) |
| 131 | self.EntryExitRecord = [self.EntryExitRecord[i] for i in indices] |
Behdad Esfahbod | d1d41bc | 2013-07-21 23:15:32 -0400 | [diff] [blame] | 132 | self.EntryExitCount = len (self.EntryExitRecord) |
| 133 | return self.EntryExitCount |
Behdad Esfahbod | 5466061 | 2013-07-21 18:16:55 -0400 | [diff] [blame] | 134 | else: |
| 135 | assert 0, "unknown format: %s" % self.Format |
| 136 | |
| 137 | @add_method(fontTools.ttLib.tables.otTables.MarkBasePos) |
| 138 | def subset (self, glyphs): |
| 139 | if self.Format == 1: |
| 140 | mark_indices = self.MarkCoverage.subset (glyphs) |
| 141 | self.MarkArray.MarkRecord = [self.MarkArray.MarkRecord[i] for i in mark_indices] |
| 142 | self.MarkArray.MarkCount = len (self.MarkArray.MarkRecord) |
| 143 | base_indices = self.BaseCoverage.subset (glyphs) |
| 144 | self.BaseArray.BaseRecord = [self.BaseArray.BaseRecord[i] for i in base_indices] |
| 145 | self.BaseArray.BaseCount = len (self.BaseArray.BaseRecord) |
| 146 | # TODO Prune empty classes |
Behdad Esfahbod | d1d41bc | 2013-07-21 23:15:32 -0400 | [diff] [blame] | 147 | return self.MarkArray.MarkCount and self.BaseArray.BaseCount |
Behdad Esfahbod | 5466061 | 2013-07-21 18:16:55 -0400 | [diff] [blame] | 148 | else: |
| 149 | assert 0, "unknown format: %s" % self.Format |
| 150 | |
| 151 | @add_method(fontTools.ttLib.tables.otTables.MarkLigPos) |
| 152 | def subset (self, glyphs): |
| 153 | if self.Format == 1: |
| 154 | mark_indices = self.MarkCoverage.subset (glyphs) |
| 155 | self.MarkArray.MarkRecord = [self.MarkArray.MarkRecord[i] for i in mark_indices] |
| 156 | self.MarkArray.MarkCount = len (self.MarkArray.MarkRecord) |
| 157 | ligature_indices = self.LigatureCoverage.subset (glyphs) |
| 158 | self.LigatureArray.LigatureAttach = [self.LigatureArray.LigatureAttach[i] for i in ligature_indices] |
| 159 | self.LigatureArray.LigatureCount = len (self.LigatureArray.LigatureAttach) |
| 160 | # TODO Prune empty classes |
Behdad Esfahbod | d1d41bc | 2013-07-21 23:15:32 -0400 | [diff] [blame] | 161 | return self.MarkArray.MarkCount and self.LigatureArray.LigatureCount |
Behdad Esfahbod | 5466061 | 2013-07-21 18:16:55 -0400 | [diff] [blame] | 162 | else: |
| 163 | assert 0, "unknown format: %s" % self.Format |
| 164 | |
| 165 | @add_method(fontTools.ttLib.tables.otTables.MarkMarkPos) |
| 166 | def subset (self, glyphs): |
| 167 | if self.Format == 1: |
| 168 | mark1_indices = self.Mark1Coverage.subset (glyphs) |
| 169 | self.Mark1Array.MarkRecord = [self.Mark1Array.MarkRecord[i] for i in mark1_indices] |
| 170 | self.Mark1Array.MarkCount = len (self.Mark1Array.MarkRecord) |
| 171 | mark2_indices = self.Mark2Coverage.subset (glyphs) |
| 172 | self.Mark2Array.Mark2Record = [self.Mark2Array.Mark2Record[i] for i in mark2_indices] |
| 173 | self.Mark2Array.MarkCount = len (self.Mark2Array.Mark2Record) |
| 174 | # TODO Prune empty classes |
Behdad Esfahbod | d1d41bc | 2013-07-21 23:15:32 -0400 | [diff] [blame] | 175 | return self.Mark1Array.MarkCount and self.Mark2Array.MarkCount |
Behdad Esfahbod | 5466061 | 2013-07-21 18:16:55 -0400 | [diff] [blame] | 176 | else: |
| 177 | assert 0, "unknown format: %s" % self.Format |
| 178 | |
Behdad Esfahbod | 02b9206 | 2013-07-21 18:40:59 -0400 | [diff] [blame] | 179 | @add_method(fontTools.ttLib.tables.otTables.ContextSubst, fontTools.ttLib.tables.otTables.ContextPos) |
Behdad Esfahbod | 5466061 | 2013-07-21 18:16:55 -0400 | [diff] [blame] | 180 | def subset (self, glyphs): |
Behdad Esfahbod | 02b9206 | 2013-07-21 18:40:59 -0400 | [diff] [blame] | 181 | if self.Format == 1: |
Behdad Esfahbod | b7fef90 | 2013-07-21 22:48:08 -0400 | [diff] [blame] | 182 | indices = self.Coverage.subset (glyphs) |
| 183 | self.SubRuleSet = [self.SubRuleSet[i] for i in indices] |
| 184 | self.SubRuleSetCount = len (self.SubRuleSet) |
| 185 | for rs in self.SubRuleSet: |
| 186 | rs.SubRule = [r for r in rs.SubRule |
| 187 | if all (g in glyphs for g in r.Input)] |
| 188 | rs.SubRuleCount = len (rs.SubRule) |
Behdad Esfahbod | d1d41bc | 2013-07-21 23:15:32 -0400 | [diff] [blame] | 189 | # Prune empty subrulesets |
| 190 | return self.SubRuleSetCount |
Behdad Esfahbod | 02b9206 | 2013-07-21 18:40:59 -0400 | [diff] [blame] | 191 | elif self.Format == 2: |
Behdad Esfahbod | d1d41bc | 2013-07-21 23:15:32 -0400 | [diff] [blame] | 192 | return self.Coverage.subset (glyphs) and self.ClassDef.subset (glyphs) |
Behdad Esfahbod | 02b9206 | 2013-07-21 18:40:59 -0400 | [diff] [blame] | 193 | elif self.Format == 3: |
Behdad Esfahbod | d1d41bc | 2013-07-21 23:15:32 -0400 | [diff] [blame] | 194 | return all (c.subset (glyphs) for c in self.Coverage) |
Behdad Esfahbod | 02b9206 | 2013-07-21 18:40:59 -0400 | [diff] [blame] | 195 | else: |
| 196 | assert 0, "unknown format: %s" % self.Format |
Behdad Esfahbod | 5466061 | 2013-07-21 18:16:55 -0400 | [diff] [blame] | 197 | |
Behdad Esfahbod | 02b9206 | 2013-07-21 18:40:59 -0400 | [diff] [blame] | 198 | @add_method(fontTools.ttLib.tables.otTables.ChainContextSubst, fontTools.ttLib.tables.otTables.ChainContextPos) |
Behdad Esfahbod | 5466061 | 2013-07-21 18:16:55 -0400 | [diff] [blame] | 199 | def subset (self, glyphs): |
Behdad Esfahbod | 02b9206 | 2013-07-21 18:40:59 -0400 | [diff] [blame] | 200 | if self.Format == 1: |
Behdad Esfahbod | b7fef90 | 2013-07-21 22:48:08 -0400 | [diff] [blame] | 201 | indices = self.Coverage.subset (glyphs) |
| 202 | self.ChainSubRuleSet = [self.ChainSubRuleSet[i] for i in indices] |
| 203 | self.ChainSubRuleSetCount = len (self.ChainSubRuleSet) |
| 204 | for rs in self.ChainSubRuleSet: |
| 205 | rs.ChainSubRule = [r for r in rs.ChainSubRule |
| 206 | if all (g in glyphs for g in r.Backtrack + r.Input + r.LookAhead)] |
| 207 | rs.ChainSubRuleCount = len (rs.ChainSubRule) |
Behdad Esfahbod | d1d41bc | 2013-07-21 23:15:32 -0400 | [diff] [blame] | 208 | # Prune empty subrulesets |
| 209 | return self.ChainSubRuleSetCount |
Behdad Esfahbod | 02b9206 | 2013-07-21 18:40:59 -0400 | [diff] [blame] | 210 | elif self.Format == 2: |
Behdad Esfahbod | d1d41bc | 2013-07-21 23:15:32 -0400 | [diff] [blame] | 211 | return self.Coverage.subset (glyphs) and \ |
| 212 | self.LookAheadClassDef.subset (glyphs) and \ |
| 213 | self.BacktrackClassDef.subset (glyphs) and \ |
| 214 | self.InputClassDef.subset (glyphs) |
Behdad Esfahbod | 02b9206 | 2013-07-21 18:40:59 -0400 | [diff] [blame] | 215 | elif self.Format == 3: |
Behdad Esfahbod | d1d41bc | 2013-07-21 23:15:32 -0400 | [diff] [blame] | 216 | return all (c.subset (glyphs) for c in self.InputCoverage + self.LookAheadCoverage + self.BacktrackCoverage) |
Behdad Esfahbod | 02b9206 | 2013-07-21 18:40:59 -0400 | [diff] [blame] | 217 | else: |
| 218 | assert 0, "unknown format: %s" % self.Format |
Behdad Esfahbod | 5466061 | 2013-07-21 18:16:55 -0400 | [diff] [blame] | 219 | |
Behdad Esfahbod | 02b9206 | 2013-07-21 18:40:59 -0400 | [diff] [blame] | 220 | @add_method(fontTools.ttLib.tables.otTables.ExtensionSubst, fontTools.ttLib.tables.otTables.ExtensionPos) |
Behdad Esfahbod | 5466061 | 2013-07-21 18:16:55 -0400 | [diff] [blame] | 221 | def subset (self, glyphs): |
| 222 | if self.Format == 1: |
Behdad Esfahbod | d1d41bc | 2013-07-21 23:15:32 -0400 | [diff] [blame] | 223 | return self.ExtSubTable.subset (glyphs) |
Behdad Esfahbod | 5466061 | 2013-07-21 18:16:55 -0400 | [diff] [blame] | 224 | else: |
| 225 | assert 0, "unknown format: %s" % self.Format |
| 226 | |
Behdad Esfahbod | 02b9206 | 2013-07-21 18:40:59 -0400 | [diff] [blame] | 227 | @add_method(fontTools.ttLib.tables.otTables.Lookup) |
| 228 | def subset (self, glyphs): |
Behdad Esfahbod | 1be5345 | 2013-07-21 22:52:15 -0400 | [diff] [blame] | 229 | self.SubTable = [s for s in self.SubTable if s.subset (glyphs)] |
Behdad Esfahbod | d1d41bc | 2013-07-21 23:15:32 -0400 | [diff] [blame] | 230 | self.SubTableCount = len (self.SubTable) |
| 231 | return self.SubTableCount |
| 232 | |
| 233 | @add_method(fontTools.ttLib.tables.otTables.LookupList) |
| 234 | def subset (self, glyphs): |
Behdad Esfahbod | 77cda41 | 2013-07-22 11:46:50 -0400 | [diff] [blame] | 235 | "Returns the indices of nonempty lookups." |
| 236 | return [i for (i,l) in enumerate (self.Lookup) if l.subset (glyphs)] |
| 237 | |
| 238 | @add_method(fontTools.ttLib.tables.otTables.LookupList) |
| 239 | def subset_lookups (self, lookup_indices): |
| 240 | self.Lookup = [self.Lookup[i] for i in lookup_indices] |
| 241 | self.LookupCount = len (self.Lookup) |
| 242 | |
| 243 | @add_method(fontTools.ttLib.tables.otTables.Feature) |
| 244 | def subset_lookups (self, lookup_indices): |
| 245 | self.LookupListIndex = [l for l in self.LookupListIndex if l in lookup_indices] |
| 246 | # Now map them. |
| 247 | self.LookupListIndex = [lookup_indices.index (l) for l in self.LookupListIndex] |
| 248 | self.LookupCount = len (self.LookupListIndex) |
Behdad Esfahbod | d1d41bc | 2013-07-21 23:15:32 -0400 | [diff] [blame] | 249 | return self.LookupCount |
Behdad Esfahbod | 5466061 | 2013-07-21 18:16:55 -0400 | [diff] [blame] | 250 | |
Behdad Esfahbod | 77cda41 | 2013-07-22 11:46:50 -0400 | [diff] [blame] | 251 | @add_method(fontTools.ttLib.tables.otTables.FeatureList) |
| 252 | def subset_lookups (self, lookup_indices): |
| 253 | "Returns the indices of nonempty features." |
| 254 | feature_indices = [i for (i,f) in enumerate (self.FeatureRecord) if f.Feature.subset_lookups (lookup_indices)] |
| 255 | self.FeatureRecord = [self.FeatureRecord[i] for i in feature_indices] |
| 256 | self.FeatureCount = len (self.FeatureRecord) |
| 257 | return feature_indices |
| 258 | |
| 259 | @add_method(fontTools.ttLib.tables.otTables.DefaultLangSys, fontTools.ttLib.tables.otTables.LangSys) |
| 260 | def subset_features (self, feature_indices): |
| 261 | if self.ReqFeatureIndex not in feature_indices: |
| 262 | self.ReqFeatureIndex = 65535 |
| 263 | self.FeatureIndex = [f for f in self.FeatureIndex if f in feature_indices] |
| 264 | self.FeatureCount = len (self.FeatureIndex) |
| 265 | return self.FeatureCount |
| 266 | |
| 267 | @add_method(fontTools.ttLib.tables.otTables.Script) |
| 268 | def subset_features (self, feature_indices): |
| 269 | if self.DefaultLangSys and not self.DefaultLangSys.subset_features (feature_indices): |
| 270 | self.DefaultLangSys = None |
| 271 | self.LangSysRecord = [l for l in self.LangSysRecord if l.LangSys.subset_features (feature_indices)] |
| 272 | self.LangSysCount = len (self.LangSysRecord) |
| 273 | return self.LangSysCount |
| 274 | |
| 275 | @add_method(fontTools.ttLib.tables.otTables.ScriptList) |
| 276 | def subset_features (self, feature_indices): |
| 277 | self.ScriptRecord = [s for s in self.ScriptRecord if s.Script.subset_features (feature_indices)] |
| 278 | self.ScriptCount = len (self.ScriptRecord) |
| 279 | return self.ScriptCount |
| 280 | |
Behdad Esfahbod | 02b9206 | 2013-07-21 18:40:59 -0400 | [diff] [blame] | 281 | @add_method(fontTools.ttLib.tables.otTables.GSUB, fontTools.ttLib.tables.otTables.GPOS) |
| 282 | def subset (self, glyphs): |
Behdad Esfahbod | 77cda41 | 2013-07-22 11:46:50 -0400 | [diff] [blame] | 283 | lookup_indices = self.LookupList.subset (glyphs) |
| 284 | self.subset_lookups (lookup_indices) |
Behdad Esfahbod | d1d41bc | 2013-07-21 23:15:32 -0400 | [diff] [blame] | 285 | return True # Retain the possibly empty table |
Behdad Esfahbod | 02b9206 | 2013-07-21 18:40:59 -0400 | [diff] [blame] | 286 | |
Behdad Esfahbod | 77cda41 | 2013-07-22 11:46:50 -0400 | [diff] [blame] | 287 | @add_method(fontTools.ttLib.tables.otTables.GSUB, fontTools.ttLib.tables.otTables.GPOS) |
| 288 | def subset_lookups (self, lookup_indices): |
| 289 | "Retrains specified lookups, then removes empty features, language systems, and scripts." |
| 290 | self.LookupList.subset_lookups (lookup_indices) |
| 291 | feature_indices = self.FeatureList.subset_lookups (lookup_indices) |
| 292 | self.ScriptList.subset_features (feature_indices) |
| 293 | |
Behdad Esfahbod | efb984a | 2013-07-21 22:26:16 -0400 | [diff] [blame] | 294 | @add_method(fontTools.ttLib.tables.otTables.GDEF) |
| 295 | def subset (self, glyphs): |
| 296 | if self.LigCaretList: |
| 297 | indices = self.LigCaretList.Coverage.subset (glyphs) |
| 298 | self.LigCaretList.LigGlyph = [self.LigCaretList.LigGlyph[i] for i in indices] |
| 299 | self.LigCaretList.LigGlyphCount = len (self.LigCaretList.LigGlyph) |
Behdad Esfahbod | d1d41bc | 2013-07-21 23:15:32 -0400 | [diff] [blame] | 300 | if not self.LigCaretList.LigGlyphCount: |
| 301 | self.LigCaretList = None |
Behdad Esfahbod | efb984a | 2013-07-21 22:26:16 -0400 | [diff] [blame] | 302 | if self.MarkAttachClassDef: |
| 303 | self.MarkAttachClassDef.classDefs = {g:v for g,v in self.MarkAttachClassDef.classDefs.items() if g in glyphs} |
Behdad Esfahbod | d1d41bc | 2013-07-21 23:15:32 -0400 | [diff] [blame] | 304 | if not self.MarkAttachClassDef.classDefs: |
| 305 | self.MarkAttachClassDef = None |
Behdad Esfahbod | efb984a | 2013-07-21 22:26:16 -0400 | [diff] [blame] | 306 | if self.GlyphClassDef: |
| 307 | self.GlyphClassDef.classDefs = {g:v for g,v in self.GlyphClassDef.classDefs.items() if g in glyphs} |
Behdad Esfahbod | d1d41bc | 2013-07-21 23:15:32 -0400 | [diff] [blame] | 308 | if not self.GlyphClassDef.classDefs: |
| 309 | self.GlyphClassDef = None |
Behdad Esfahbod | efb984a | 2013-07-21 22:26:16 -0400 | [diff] [blame] | 310 | if self.AttachList: |
| 311 | indices = self.AttachList.Coverage.subset (glyphs) |
| 312 | self.AttachList.AttachPoint = [self.AttachList.AttachPoint[i] for i in indices] |
| 313 | self.AttachList.GlyphCount = len (self.AttachList.AttachPoint) |
Behdad Esfahbod | d1d41bc | 2013-07-21 23:15:32 -0400 | [diff] [blame] | 314 | if not self.AttachList.GlyphCount: |
| 315 | self.AttachList = None |
| 316 | return True # Retain the possibly empty table |
Behdad Esfahbod | efb984a | 2013-07-21 22:26:16 -0400 | [diff] [blame] | 317 | |
| 318 | |
Behdad Esfahbod | 02b9206 | 2013-07-21 18:40:59 -0400 | [diff] [blame] | 319 | if __name__ == '__main__': |
| 320 | |
| 321 | import sys |
| 322 | |
Behdad Esfahbod | 4ae8171 | 2013-07-22 11:57:13 -0400 | [diff] [blame] | 323 | verbose = False |
| 324 | if "--verbose" in sys.argv: |
| 325 | verbose = True |
| 326 | sys.argv.remove ("--verbose") |
Behdad Esfahbod | 350a527 | 2013-07-22 12:02:16 -0400 | [diff] [blame] | 327 | xml = False |
| 328 | if "--xml" in sys.argv: |
| 329 | xml = True |
| 330 | sys.argv.remove ("--xml") |
Behdad Esfahbod | 4ae8171 | 2013-07-22 11:57:13 -0400 | [diff] [blame] | 331 | |
Behdad Esfahbod | 02b9206 | 2013-07-21 18:40:59 -0400 | [diff] [blame] | 332 | if len (sys.argv) < 3: |
| 333 | print >>sys.stderr, "usage: pyotlss.py font-file glyph..." |
| 334 | sys.exit (1) |
| 335 | |
| 336 | fontfile = sys.argv[1] |
| 337 | glyphs = sys.argv[2:] |
| 338 | |
| 339 | font = fontTools.ttx.TTFont (fontfile) |
| 340 | |
| 341 | names = font.getGlyphNames() |
| 342 | # Convert to glyph names |
| 343 | glyphs = [g if g in names else font.getGlyphName(int(g)) for g in glyphs] |
| 344 | |
Behdad Esfahbod | 350a527 | 2013-07-22 12:02:16 -0400 | [diff] [blame] | 345 | if xml: |
Behdad Esfahbod | 4ae8171 | 2013-07-22 11:57:13 -0400 | [diff] [blame] | 346 | import xmlWriter |
| 347 | writer = xmlWriter.XMLWriter (sys.stdout) |
Behdad Esfahbod | 9d02c2d | 2013-07-22 11:08:37 -0400 | [diff] [blame] | 348 | for tag in ['GDEF', 'GSUB', 'GPOS']: |
| 349 | if tag not in font: |
Behdad Esfahbod | 02b9206 | 2013-07-21 18:40:59 -0400 | [diff] [blame] | 350 | continue |
Behdad Esfahbod | 9d02c2d | 2013-07-22 11:08:37 -0400 | [diff] [blame] | 351 | if not font[tag].table.subset (glyphs): |
| 352 | del font[tag] |
Behdad Esfahbod | 4ae8171 | 2013-07-22 11:57:13 -0400 | [diff] [blame] | 353 | else: |
Behdad Esfahbod | 350a527 | 2013-07-22 12:02:16 -0400 | [diff] [blame] | 354 | if xml: |
Behdad Esfahbod | 4ae8171 | 2013-07-22 11:57:13 -0400 | [diff] [blame] | 355 | writer.begintag (tag) |
| 356 | writer.newline () |
| 357 | font[tag].toXML(writer, font) |
| 358 | writer.endtag (tag) |
| 359 | writer.newline () |
Behdad Esfahbod | 350a527 | 2013-07-22 12:02:16 -0400 | [diff] [blame] | 360 | if verbose: |
| 361 | print tag, "is %d bytes now." % len (font[tag].compile (font)) |
Behdad Esfahbod | d1d41bc | 2013-07-21 23:15:32 -0400 | [diff] [blame] | 362 | |
Behdad Esfahbod | 77cda41 | 2013-07-22 11:46:50 -0400 | [diff] [blame] | 363 | font.save (fontfile + '.subset') |