예제 #1
0
def buildFeatureRecord(featureTag, lookupListIndices):
    """Build a FeatureRecord."""
    fr = ot.FeatureRecord()
    fr.FeatureTag = featureTag
    fr.Feature = ot.Feature()
    fr.Feature.LookupListIndex = lookupListIndices
    return fr
예제 #2
0
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
예제 #3
0
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
예제 #4
0
    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)
예제 #5
0
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
예제 #6
0
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
예제 #7
0
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
예제 #8
0
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
예제 #9
0
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
예제 #10
0
    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))
예제 #11
0
    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
예제 #12
0
    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