def buildFeatureRecord(featureTag, lookupListIndices): """Build a FeatureRecord.""" fr = ot.FeatureRecord() fr.FeatureTag = featureTag fr.Feature = ot.Feature() fr.Feature.LookupListIndex = lookupListIndices return fr
def parseFeatureList(lines, lookupMap=None, featureMap=None): self = ot.FeatureList() self.FeatureRecord = [] with lines.between('feature table'): for line in lines: name, featureTag, lookups = line if featureMap is not None: assert name not in featureMap, "Duplicate feature name: %s" % name featureMap[name] = len(self.FeatureRecord) # If feature name is integer, make sure it matches its index. try: assert int(name) == len(self.FeatureRecord), "%d %d" % (name, len(self.FeatureRecord)) except ValueError: pass featureRec = ot.FeatureRecord() featureRec.FeatureTag = featureTag featureRec.Feature = ot.Feature() self.FeatureRecord.append(featureRec) feature = featureRec.Feature feature.FeatureParams = None syms = stripSplitComma(lookups) feature.LookupListIndex = theList = [None] * len(syms) for i,sym in enumerate(syms): setReference(mapLookup, lookupMap, sym, setitem, theList, i) feature.LookupCount = len(feature.LookupListIndex) self.FeatureCount = len(self.FeatureRecord) return self
def merge(self, m, tables): assert len(tables) == len(m.duplicateGlyphsPerFont) for i, (table, dups) in enumerate(zip(tables, m.duplicateGlyphsPerFont)): if not dups: continue assert (table is not None and table is not NotImplemented ), "Have duplicates to resolve for font %d but no GSUB: %s" % ( i + 1, dups) synthFeature = None synthLookup = None for script in table.table.ScriptList.ScriptRecord: if script.ScriptTag == 'DFLT': continue # XXX for langsys in [script.Script.DefaultLangSys] + [ l.LangSys for l in script.Script.LangSysRecord ]: if langsys is None: continue # XXX Create! feature = [ v for v in langsys.FeatureIndex if v.FeatureTag == 'locl' ] assert len(feature) <= 1 if feature: feature = feature[0] else: if not synthFeature: synthFeature = otTables.FeatureRecord() synthFeature.FeatureTag = 'locl' f = synthFeature.Feature = otTables.Feature() f.FeatureParams = None f.LookupCount = 0 f.LookupListIndex = [] langsys.FeatureIndex.append(synthFeature) langsys.FeatureIndex.sort(key=lambda v: v.FeatureTag) table.table.FeatureList.FeatureRecord.append( synthFeature) table.table.FeatureList.FeatureCount += 1 feature = synthFeature if not synthLookup: subtable = otTables.SingleSubst() subtable.mapping = dups synthLookup = otTables.Lookup() synthLookup.LookupFlag = 0 synthLookup.LookupType = 1 synthLookup.SubTableCount = 1 synthLookup.SubTable = [subtable] if table.table.LookupList is None: # mtiLib uses None as default value for LookupList, # while feaLib points to an empty array with count 0 # TODO: make them do the same table.table.LookupList = otTables.LookupList() table.table.LookupList.Lookup = [] table.table.LookupList.LookupCount = 0 table.table.LookupList.Lookup.append(synthLookup) table.table.LookupList.LookupCount += 1 feature.Feature.LookupListIndex[:0] = [synthLookup] feature.Feature.LookupCount += 1 DefaultTable.merge(self, m, tables) return self
def _add_feature(self, font: Font, table: otTables.GPOS, feature_tag: str, lookup_indices: List[int]) -> None: logger.debug('Adding "%s" to: "%s" %s', feature_tag, font, self._to_str(glyph_ids=True)) assert not Font._has_ottable_feature(table, feature_tag) features = table.FeatureList.FeatureRecord feature_index = len(features) logger.info('Adding Feature "%s" at index %d for lookup %s', feature_tag, feature_index, lookup_indices) feature_record = otTables.FeatureRecord() feature_record.FeatureTag = feature_tag feature_record.Feature = otTables.Feature() feature_record.Feature.LookupListIndex = lookup_indices feature_record.Feature.LookupCount = len(lookup_indices) features.append(feature_record) scripts = table.ScriptList.ScriptRecord for script_record in scripts: default_lang_sys = script_record.Script.DefaultLangSys if default_lang_sys: logger.debug( "Adding Feature index %d to script '%s' DefaultLangSys", feature_index, script_record.ScriptTag) default_lang_sys.FeatureIndex.append(feature_index) for lang_sys in script_record.Script.LangSysRecord: logger.debug( "Adding Feature index %d to script '%s' LangSys '%s'", feature_index, script_record.ScriptTag, lang_sys.LangSysTag) lang_sys.LangSys.FeatureIndex.append(feature_index)
def buildFeatureRecord(featureTag, lookupListIndices): """Build a FeatureRecord.""" fr = ot.FeatureRecord() fr.FeatureTag = featureTag fr.Feature = ot.Feature() fr.Feature.LookupListIndex = lookupListIndices fr.Feature.populateDefaults() return fr
def merge(self, m, tables): assert len(tables) == len(m.duplicateGlyphsPerFont) for i, (table, dups) in enumerate(zip(tables, m.duplicateGlyphsPerFont)): if not dups: continue assert ( table is not None and table is not NotImplemented ), "Have duplicates to resolve for font %d but no GSUB" % (i + 1) lookupMap = dict((id(v), v) for v in table.table.LookupList.Lookup) featureMap = dict( (id(v), v) for v in table.table.FeatureList.FeatureRecord) synthFeature = None synthLookup = None for script in table.table.ScriptList.ScriptRecord: if script.ScriptTag == 'DFLT': continue # XXX for langsys in [script.Script.DefaultLangSys] + [ l.LangSys for l in script.Script.LangSysRecord ]: feature = [ featureMap[v] for v in langsys.FeatureIndex if featureMap[v].FeatureTag == 'locl' ] assert len(feature) <= 1 if feature: feature = feature[0] else: if not synthFeature: synthFeature = otTables.FeatureRecord() synthFeature.FeatureTag = 'locl' f = synthFeature.Feature = otTables.Feature() f.FeatureParams = None f.LookupCount = 0 f.LookupListIndex = [] langsys.FeatureIndex.append(id(synthFeature)) featureMap[id(synthFeature)] = synthFeature langsys.FeatureIndex.sort( key=lambda v: featureMap[v].FeatureTag) table.table.FeatureList.FeatureRecord.append( synthFeature) table.table.FeatureList.FeatureCount += 1 feature = synthFeature if not synthLookup: subtable = otTables.SingleSubst() subtable.mapping = dups synthLookup = otTables.Lookup() synthLookup.LookupFlag = 0 synthLookup.LookupType = 1 synthLookup.SubTableCount = 1 synthLookup.SubTable = [subtable] table.table.LookupList.Lookup.append(synthLookup) table.table.LookupList.LookupCount += 1 feature.Feature.LookupListIndex[:0] = [id(synthLookup)] feature.Feature.LookupCount += 1 DefaultTable.merge(self, m, tables) return self
def merge(self, m, tables): assert len(tables) == len(m.duplicateGlyphsPerFont) for i,(table,dups) in enumerate(zip(tables, m.duplicateGlyphsPerFont)): if not dups: continue if table is None or table is NotImplemented: # Checks whether the dups are equivalent or not. # Discard gid if its shape is not equal to that of oldgid. for oldgid, gid in dups.items(): if not isGlyphSame(m.fonts, oldgid, gid): oldgname, oldidx = getGlyphNameAndFontIndex(oldgid) gname, idx = getGlyphNameAndFontIndex(gid) log.warn("%s:<%s> is dropped and replaced by %s:<%s>" % (m.fontfiles[idx], gname, m.fontfiles[oldidx], oldgname)) continue lookupMap = {id(v):v for v in table.table.LookupList.Lookup} featureMap = {id(v):v for v in table.table.FeatureList.FeatureRecord} synthFeature = None synthLookup = None for script in table.table.ScriptList.ScriptRecord: if script.ScriptTag == 'DFLT': continue # XXX for langsys in [script.Script.DefaultLangSys] + [l.LangSys for l in script.Script.LangSysRecord]: if langsys is None: continue # XXX Create! feature = [featureMap[v] for v in langsys.FeatureIndex if featureMap[v].FeatureTag == 'locl'] assert len(feature) <= 1 if feature: feature = feature[0] else: if not synthFeature: synthFeature = otTables.FeatureRecord() synthFeature.FeatureTag = 'locl' f = synthFeature.Feature = otTables.Feature() f.FeatureParams = None f.LookupCount = 0 f.LookupListIndex = [] langsys.FeatureIndex.append(id(synthFeature)) featureMap[id(synthFeature)] = synthFeature langsys.FeatureIndex.sort(key=lambda v: featureMap[v].FeatureTag) table.table.FeatureList.FeatureRecord.append(synthFeature) table.table.FeatureList.FeatureCount += 1 feature = synthFeature if not synthLookup: subtable = otTables.SingleSubst() subtable.mapping = dups synthLookup = otTables.Lookup() synthLookup.LookupFlag = 0 synthLookup.LookupType = 1 synthLookup.SubTableCount = 1 synthLookup.SubTable = [subtable] table.table.LookupList.Lookup.append(synthLookup) table.table.LookupList.LookupCount += 1 feature.Feature.LookupListIndex[:0] = [id(synthLookup)] feature.Feature.LookupCount += 1 DefaultTable.merge(self, m, tables) return self
def create_feature_list(feature_tag, lookup_count): """Create a FeatureList for the GSUB table.""" feature_record = otTables.FeatureRecord() feature_record.FeatureTag = feature_tag feature_record.Feature = otTables.Feature() feature_record.Feature.LookupCount = lookup_count feature_record.Feature.LookupListIndex = range(lookup_count) feature_record.Feature.FeatureParams = None feature_list = otTables.FeatureList() feature_list.FeatureCount = 1 feature_list.FeatureRecord = [feature_record] return feature_list
def mergeFeatureLists(lst): d = {} for l in lst: for f in l: tag = f.FeatureTag if tag not in d: d[tag] = [] d[tag].append(f.Feature) ret = [] for tag in sorted(d.keys()): rec = otTables.FeatureRecord() rec.FeatureTag = tag rec.Feature = mergeFeatures(d[tag]) ret.append(rec) return ret
featureRecords = table.FeatureList.FeatureRecord for script in table.ScriptList.ScriptRecord: print(" Script:", script.ScriptTag) if not script.Script: print(" Null script.") continue languages = list(script.Script.LangSysRecord) if script.Script.DefaultLangSys: defaultlangsys = otTables.LangSysRecord() defaultlangsys.LangSysTag = "default" defaultlangsys.LangSys = script.Script.DefaultLangSys languages.insert(0, defaultlangsys) for langsys in languages: print(" Language:", langsys.LangSysTag) if not langsys.LangSys: print(" Null language.") continue features = [ featureRecords[index] for index in langsys.LangSys.FeatureIndex ] if langsys.LangSys.ReqFeatureIndex != 0xFFFF: record = featureRecords[langsys.LangSys.ReqFeatureIndex] requiredfeature = otTables.FeatureRecord() requiredfeature.FeatureTag = 'required(%s)' % record.FeatureTag requiredfeature.Feature = record.Feature features.insert(0, requiredfeature) for feature in features: print(" Feature:", feature.FeatureTag) lookups = feature.Feature.LookupListIndex print(" Lookups:", ','.join(str(l) for l in lookups))
def makeTable(self, tag): table = getattr(otTables, tag, None)() table.Version = 1.0 table.ScriptList = otTables.ScriptList() table.ScriptList.ScriptRecord = [] table.FeatureList = otTables.FeatureList() table.FeatureList.FeatureRecord = [] table.LookupList = otTables.LookupList() table.LookupList.Lookup = [] for lookup in self.lookups_: lookup.lookup_index = None for i, lookup_builder in enumerate(self.lookups_): if lookup_builder.table != tag: continue # If multiple lookup builders would build equivalent lookups, # emit them only once. This is quadratic in the number of lookups, # but the checks are cheap. If performance ever becomes an issue, # we could hash the lookup content and only compare those with # the same hash value. equivalent_builder = None for other_builder in self.lookups_[:i]: if lookup_builder.equals(other_builder): equivalent_builder = other_builder if equivalent_builder is not None: lookup_builder.lookup_index = equivalent_builder.lookup_index continue lookup_builder.lookup_index = len(table.LookupList.Lookup) table.LookupList.Lookup.append(lookup_builder.build()) # Build a table for mapping (tag, lookup_indices) to feature_index. # For example, ('liga', (2,3,7)) --> 23. feature_indices = {} required_feature_indices = {} # ('latn', 'DEU') --> 23 scripts = {} # 'latn' --> {'DEU': [23, 24]} for feature #23,24 for key, lookups in sorted(self.features_.items()): script, lang, feature_tag = key # l.lookup_index will be None when a lookup is not needed # for the table under construction. For example, substitution # rules will have no lookup_index while building GPOS tables. lookup_indices = tuple([ l.lookup_index for l in lookups if l.lookup_index is not None ]) if len(lookup_indices) == 0: continue feature_key = (feature_tag, lookup_indices) feature_index = feature_indices.get(feature_key) if feature_index is None: feature_index = len(table.FeatureList.FeatureRecord) frec = otTables.FeatureRecord() frec.FeatureTag = feature_tag frec.Feature = otTables.Feature() frec.Feature.FeatureParams = None frec.Feature.LookupListIndex = lookup_indices frec.Feature.LookupCount = len(lookup_indices) table.FeatureList.FeatureRecord.append(frec) feature_indices[feature_key] = feature_index scripts.setdefault(script, {}).setdefault(lang, []).append(feature_index) if self.required_features_.get((script, lang)) == feature_tag: required_feature_indices[(script, lang)] = feature_index # Build ScriptList. for script, lang_features in sorted(scripts.items()): srec = otTables.ScriptRecord() srec.ScriptTag = script srec.Script = otTables.Script() srec.Script.DefaultLangSys = None srec.Script.LangSysRecord = [] for lang, feature_indices in sorted(lang_features.items()): langrec = otTables.LangSysRecord() langrec.LangSys = otTables.LangSys() langrec.LangSys.LookupOrder = None req_feature_index = \ required_feature_indices.get((script, lang)) if req_feature_index is None: langrec.LangSys.ReqFeatureIndex = 0xFFFF else: langrec.LangSys.ReqFeatureIndex = req_feature_index langrec.LangSys.FeatureIndex = [ i for i in feature_indices if i != req_feature_index ] langrec.LangSys.FeatureCount = \ len(langrec.LangSys.FeatureIndex) if lang == "dflt": srec.Script.DefaultLangSys = langrec.LangSys else: langrec.LangSysTag = lang srec.Script.LangSysRecord.append(langrec) srec.Script.LangSysCount = len(srec.Script.LangSysRecord) table.ScriptList.ScriptRecord.append(srec) table.ScriptList.ScriptCount = len(table.ScriptList.ScriptRecord) table.FeatureList.FeatureCount = len(table.FeatureList.FeatureRecord) table.LookupList.LookupCount = len(table.LookupList.Lookup) return table
def makeTable(self, tag): table = getattr(otTables, tag, None)() table.Version = 1.0 table.ScriptList = otTables.ScriptList() table.ScriptList.ScriptRecord = [] table.FeatureList = otTables.FeatureList() table.FeatureList.FeatureRecord = [] table.LookupList = otTables.LookupList() table.LookupList.Lookup = self.buildLookups_(tag) # Build a table for mapping (tag, lookup_indices) to feature_index. # For example, ('liga', (2,3,7)) --> 23. feature_indices = {} required_feature_indices = {} # ('latn', 'DEU') --> 23 scripts = {} # 'latn' --> {'DEU': [23, 24]} for feature #23,24 for key, lookups in sorted(self.features_.items()): script, lang, feature_tag = key # l.lookup_index will be None when a lookup is not needed # for the table under construction. For example, substitution # rules will have no lookup_index while building GPOS tables. lookup_indices = tuple([l.lookup_index for l in lookups if l.lookup_index is not None]) if len(lookup_indices) == 0: continue feature_key = (feature_tag, lookup_indices) feature_index = feature_indices.get(feature_key) if feature_index is None: feature_index = len(table.FeatureList.FeatureRecord) frec = otTables.FeatureRecord() frec.FeatureTag = feature_tag frec.Feature = otTables.Feature() frec.Feature.FeatureParams = None frec.Feature.LookupListIndex = lookup_indices frec.Feature.LookupCount = len(lookup_indices) table.FeatureList.FeatureRecord.append(frec) feature_indices[feature_key] = feature_index scripts.setdefault(script, {}).setdefault(lang, []).append( feature_index) if self.required_features_.get((script, lang)) == feature_tag: required_feature_indices[(script, lang)] = feature_index # Build ScriptList. for script, lang_features in sorted(scripts.items()): srec = otTables.ScriptRecord() srec.ScriptTag = script srec.Script = otTables.Script() srec.Script.DefaultLangSys = None srec.Script.LangSysRecord = [] for lang, feature_indices in sorted(lang_features.items()): langrec = otTables.LangSysRecord() langrec.LangSys = otTables.LangSys() langrec.LangSys.LookupOrder = None req_feature_index = \ required_feature_indices.get((script, lang)) if req_feature_index is None: langrec.LangSys.ReqFeatureIndex = 0xFFFF else: langrec.LangSys.ReqFeatureIndex = req_feature_index langrec.LangSys.FeatureIndex = [i for i in feature_indices if i != req_feature_index] langrec.LangSys.FeatureCount = \ len(langrec.LangSys.FeatureIndex) if lang == "dflt": srec.Script.DefaultLangSys = langrec.LangSys else: langrec.LangSysTag = lang srec.Script.LangSysRecord.append(langrec) srec.Script.LangSysCount = len(srec.Script.LangSysRecord) table.ScriptList.ScriptRecord.append(srec) table.ScriptList.ScriptCount = len(table.ScriptList.ScriptRecord) table.FeatureList.FeatureCount = len(table.FeatureList.FeatureRecord) table.LookupList.LookupCount = len(table.LookupList.Lookup) return table