Example #1
0
def buildGSUB():
    """Build a GSUB table from scratch."""
    fontTable = newTable("GSUB")
    gsub = fontTable.table = ot.GSUB()
    gsub.Version = 0x00010001  # allow gsub.FeatureVariations

    gsub.ScriptList = ot.ScriptList()
    gsub.ScriptList.ScriptRecord = []
    gsub.FeatureList = ot.FeatureList()
    gsub.FeatureList.FeatureRecord = []
    gsub.LookupList = ot.LookupList()
    gsub.LookupList.Lookup = []

    srec = ot.ScriptRecord()
    srec.ScriptTag = 'DFLT'
    srec.Script = ot.Script()
    srec.Script.DefaultLangSys = None
    srec.Script.LangSysRecord = []

    langrec = ot.LangSysRecord()
    langrec.LangSys = ot.LangSys()
    langrec.LangSys.ReqFeatureIndex = 0xFFFF
    langrec.LangSys.FeatureIndex = [0]
    srec.Script.DefaultLangSys = langrec.LangSys

    gsub.ScriptList.ScriptRecord.append(srec)
    gsub.FeatureVariations = None

    return fontTable
Example #2
0
def create_lookup_list(lookups):
    """Create a LookupList for the GSUB table."""
    lookup_list = otTables.LookupList()
    lookup_list.LookupCount = len(lookups)
    lookup_list.Lookup = lookups

    return lookup_list
Example #3
0
def add_gsub_to_font(fontfile):
    """Adds an empty GSUB table to a font."""
    font = ttLib.TTFont(fontfile)
    gsub_table = ttLib.getTableClass('GSUB')('GSUB')
    gsub_table.table = otTables.GSUB()
    gsub_table.table.Version = 1.0
    gsub_table.table.ScriptList = otTables.ScriptList()
    gsub_table.table.ScriptCount = 1
    gsub_table.table.LookupList = otTables.LookupList()
    gsub_table.table.LookupList.LookupCount = 0
    gsub_table.table.LookupList.Lookup = []
    gsub_table.table.FeatureList = otTables.FeatureList()
    gsub_table.table.FeatureList.FeatureCount = 0
    gsub_table.table.LookupList.FeatureRecord = []

    script_record = otTables.ScriptRecord()
    script_record.ScriptTag = get_opentype_script_tag(fontfile)
    script_record.Script = otTables.Script()
    script_record.Script.LangSysCount = 0
    script_record.Script.LangSysRecord = []

    default_lang_sys = otTables.DefaultLangSys()
    default_lang_sys.FeatureIndex = []
    default_lang_sys.FeatureCount = 0
    default_lang_sys.LookupOrder = None
    default_lang_sys.ReqFeatureIndex = 65535
    script_record.Script.DefaultLangSys = default_lang_sys

    gsub_table.table.ScriptList.ScriptRecord = [script_record]

    font['GSUB'] = gsub_table

    target_file = tempfile.gettempdir() + '/' + os.path.basename(fontfile)
    font.save(target_file)
    return target_file
Example #4
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
def doit(args):
    font = args.ifont
    args.type = args.type.upper()

    for tag in ('GSUB', 'GPOS'):
        if tag == args.type or args.type == 'BOTH':
            table = ttLib.getTableClass(tag)()
            t = getattr(otTables, tag, None)()
            t.Version = 1.0
            t.ScriptList = otTables.ScriptList()
            t.ScriptList.ScriptRecord = []
            t.FeatureList = otTables.FeatureList()
            t.FeatureList.FeatureRecord = []
            t.LookupList = otTables.LookupList()
            t.LookupList.Lookup = []
            srec = otTables.ScriptRecord()
            srec.ScriptTag = args.script
            srec.Script = otTables.Script()
            srec.Script.DefaultLangSys = None
            srec.Script.LangSysRecord = []
            t.ScriptList.ScriptRecord.append(srec)
            t.ScriptList.ScriptCount = 1
            t.FeatureList.FeatureCount = 0
            t.LookupList.LookupCount = 0
            table.table = t
            font[tag] = table

    return font
Example #6
0
def parseGSUBGPOS(lines, font, tableTag):
	container = ttLib.getTableClass(tableTag)()
	lookupMap = DeferredMapping()
	featureMap = DeferredMapping()
	assert tableTag in ('GSUB', 'GPOS')
	log.debug("Parsing %s", tableTag)
	self = getattr(ot, tableTag)()
	self.Version = 0x00010000
	fields = {
		'script table begin':
		('ScriptList',
		 lambda lines: parseScriptList (lines, featureMap)),
		'feature table begin':
		('FeatureList',
		 lambda lines: parseFeatureList (lines, lookupMap, featureMap)),
		'lookup':
		('LookupList',
		 None),
	}
	for attr,parser in fields.values():
		setattr(self, attr, None)
	while lines.peek() is not None:
		typ = lines.peek()[0].lower()
		if typ not in fields:
			log.debug('Skipping %s', lines.peek())
			next(lines)
			continue
		attr,parser = fields[typ]
		if typ == 'lookup':
			if self.LookupList is None:
				self.LookupList = ot.LookupList()
				self.LookupList.Lookup = []
			_, name, _ = lines.peek()
			lookup = parseLookup(lines, tableTag, font, lookupMap)
			if lookupMap is not None:
				assert name not in lookupMap, "Duplicate lookup name: %s" % name
				lookupMap[name] = len(self.LookupList.Lookup)
			else:
				assert int(name) == len(self.LookupList.Lookup), "%d %d" % (name, len(self.Lookup))
			self.LookupList.Lookup.append(lookup)
		else:
			assert getattr(self, attr) is None, attr
			setattr(self, attr, parser(lines))
	if self.LookupList:
		self.LookupList.LookupCount = len(self.LookupList.Lookup)
	if lookupMap is not None:
		lookupMap.applyDeferredMappings()
	if featureMap is not None:
		featureMap.applyDeferredMappings()
	container.table = self
	return container
Example #7
0
 def _add_gpos_table(self):
     logger.info('Adding GPOS table to "%s"', self)
     ttfont = self.ttfont
     assert ttfont.get('GPOS') is None
     table = otTables.GPOS()
     table.Version = 0x00010000
     table.ScriptList = otTables.ScriptList()
     table.ScriptList.ScriptRecord = [self.create_script_record()]
     table.FeatureList = otTables.FeatureList()
     table.FeatureList.FeatureRecord = []
     table.LookupList = otTables.LookupList()
     table.LookupList.Lookup = []
     gpos = ttfont['GPOS'] = newTable('GPOS')
     gpos.table = table
     return gpos
Example #8
0
def parseGSUBGPOS(lines, font, tableTag):
	lookupMap = None#{} Until we support forward references...
	featureMap = {}
	assert tableTag in ('GSUB', 'GPOS')
	debug("Parsing", tableTag)
	self = getattr(ot, tableTag)()
	self.Version = 1.0
	fields = {
		'script table begin':
		('ScriptList',
		 lambda lines: parseScriptList (lines, featureMap)),
		'feature table begin':
		('FeaturetList',
		 lambda lines: parseFeatureList (lines, lookupMap, featureMap)),
		'lookup':
		('LookupList',
		 None),
	}
	for attr,parser in fields.values():
		setattr(self, attr, None)
	while lines.peek() is not None:
		typ = lines.peek()[0].lower()
		if typ not in fields:
			debug ('Skipping', lines.peek())
			next(lines)
			continue
		attr,parser = fields[typ]
		if typ == 'lookup':
			if self.LookupList is None:
				self.LookupList = ot.LookupList()
				self.LookupList.Lookup = []
			_, name, _ = lines.peek()
			lookup = parseLookup(lines, tableTag, font, lookupMap)
			if lookupMap:
				assert name not in lookupMap, "Duplicate lookup name: %s" % name
				lookupMap[name] = len(self.LookupList.Lookup)
			else:
				assert int(name) == len(self.LookupList.Lookup), "%d %d" % (name, len(self.Lookup))
			self.LookupList.Lookup.append(lookup)
		else:
			assert getattr(self, attr) is None, attr
			setattr(self, attr, parser(lines))
	if self.LookupList:
		self.LookupList.LookupCount = len(self.LookupList.Lookup)
	return self
Example #9
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
Example #10
0
parser.add_argument('infont', help='Input font file')
parser.add_argument('outfont', help='Output font file')
parser.add_argument('-s','--script',default='DFLT', help='Script tag to generate [DFLT]')
parser.add_argument('-t','--type',default='both', help='Table to create: gpos, gsub, [both]')
args = parser.parse_args()

inf = ttLib.TTFont(args.infont)
for tag in ('GSUB', 'GPOS') :
    if tag.lower() == args.type or args.type == 'both' :
        table = ttLib.getTableClass(tag)()
        t = getattr(otTables, tag, None)()
        t.Version = 1.0
        t.ScriptList = otTables.ScriptList()
        t.ScriptList.ScriptRecord = []
        t.FeatureList = otTables.FeatureList()
        t.FeatureList.FeatureRecord = []
        t.LookupList = otTables.LookupList()
        t.LookupList.Lookup = []
        srec = otTables.ScriptRecord()
        srec.ScriptTag = args.script
        srec.Script = otTables.Script()
        srec.Script.DefaultLangSys = None
        srec.Script.LangSysRecord = []
        t.ScriptList.ScriptRecord.append(srec)
        t.ScriptList.ScriptCount = 1
        t.FeatureList.FeatureCount = 0
        t.LookupList.LookupCount = 0
        table.table = t
        inf[tag] = table
inf.save(args.outfont)
Example #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 = 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