예제 #1
0
def create_lookup(table, font, flag=0):
    """Create a Lookup based on mapping table."""
    cmap = font_data.get_cmap(font)

    ligatures = {}
    for output, (ch1, ch2) in table.iteritems():
        output = cmap[output]
        ch1 = get_glyph_name_or_create(ch1, font)
        ch2 = get_glyph_name_or_create(ch2, font)

        ligature = otTables.Ligature()
        ligature.CompCount = 2
        ligature.Component = [ch2]
        ligature.LigGlyph = output

        try:
            ligatures[ch1].append(ligature)
        except KeyError:
            ligatures[ch1] = [ligature]

    ligature_subst = otTables.LigatureSubst()
    ligature_subst.ligatures = ligatures

    lookup = otTables.Lookup()
    lookup.LookupType = 4
    lookup.LookupFlag = flag
    lookup.SubTableCount = 1
    lookup.SubTable = [ligature_subst]

    return lookup
예제 #2
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
예제 #3
0
def add_ligature(font, codes):
    if 'GSUB' not in font:
        ligature_subst = otTables.LigatureSubst()
        ligature_subst.ligatures = {}

        lookup = otTables.Lookup()
        lookup.LookupType = 4
        lookup.LookupFlag = 0
        lookup.SubTableCount = 1
        lookup.SubTable = [ligature_subst]

        font['GSUB'] = add_emoji_gsub.create_simple_gsub([lookup])
    else:
        lookup = font['GSUB'].table.LookupList.Lookup[0]
        assert lookup.LookupType == 4
        assert lookup.LookupFlag == 0

    ligatures = lookup.SubTable[0].ligatures

    lig = otTables.Ligature()
    lig.CompCount = len(codes)
    lig.Component = [glyph_name([code]) for code in codes[1:]]
    lig.LigGlyph = glyph_name(codes)

    first = "%04X" % int(codes[0], 16)
    try:
        ligatures[first].append(lig)
    except KeyError:
        ligatures[first] = [lig]
예제 #4
0
def buildLookup(subtables, flags=0, markFilterSet=None):
    if subtables is None:
        return None
    subtables = [st for st in subtables if st is not None]
    if not subtables:
        return None
    assert all(t.LookupType == subtables[0].LookupType for t in subtables), \
        ("all subtables must have the same LookupType; got %s" %
         repr([t.LookupType for t in subtables]))
    self = ot.Lookup()
    self.LookupType = subtables[0].LookupType
    self.LookupFlag = flags
    self.SubTable = subtables
    self.SubTableCount = len(self.SubTable)
    if markFilterSet is not None:
        assert self.LookupFlag & LOOKUP_FLAG_USE_MARK_FILTERING_SET, \
            ("if markFilterSet is not None, flags must set "
             "LOOKUP_FLAG_USE_MARK_FILTERING_SET; flags=0x%04x" % flags)
        assert isinstance(markFilterSet, int), markFilterSet
        self.MarkFilteringSet = markFilterSet
    else:
        assert (self.LookupFlag & LOOKUP_FLAG_USE_MARK_FILTERING_SET) == 0, \
            ("if markFilterSet is None, flags must not set "
             "LOOKUP_FLAG_USE_MARK_FILTERING_SET; flags=0x%04x" % flags)
    return self
예제 #5
0
def get_gsub_ligature_lookup(font):
    """If the font does not have a GSUB table, create one with a ligature
  substitution lookup.  If it does, ensure the first lookup is a properly
  initialized ligature substitution lookup.  Return the lookup."""

    # The template might include more lookups after lookup 0, if it has a
    # GSUB table.
    if 'GSUB' not in font:
        ligature_subst = otTables.LigatureSubst()
        ligature_subst.ligatures = {}

        lookup = otTables.Lookup()
        lookup.LookupType = 4
        lookup.LookupFlag = 0
        lookup.SubTableCount = 1
        lookup.SubTable = [ligature_subst]

        font['GSUB'] = add_emoji_gsub.create_simple_gsub([lookup])
    else:
        lookup = font['GSUB'].table.LookupList.Lookup[0]
        assert lookup.LookupFlag == 0

        # importXML doesn't fully init GSUB structures, so help it out
        st = lookup.SubTable[0]
        if not hasattr(lookup, 'LookupType'):
            assert st.LookupType == 4
            setattr(lookup, 'LookupType', 4)

        if not hasattr(st, 'ligatures'):
            setattr(st, 'ligatures', {})

    return lookup
예제 #6
0
def add_ligature(font, seq, name):
    if 'GSUB' not in font:
        ligature_subst = otTables.LigatureSubst()
        ligature_subst.ligatures = {}

        lookup = otTables.Lookup()
        lookup.LookupType = 4
        lookup.LookupFlag = 0
        lookup.SubTableCount = 1
        lookup.SubTable = [ligature_subst]

        font['GSUB'] = add_emoji_gsub.create_simple_gsub([lookup])
    else:
        lookup = font['GSUB'].table.LookupList.Lookup[0]
        assert lookup.LookupType == 4
        assert lookup.LookupFlag == 0

    ligatures = lookup.SubTable[0].ligatures

    lig = otTables.Ligature()
    lig.CompCount = len(seq)
    lig.Component = seq[1:]
    lig.LigGlyph = name

    first = seq[0]
    try:
        ligatures[first].append(lig)
    except KeyError:
        ligatures[first] = [lig]
예제 #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
        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
예제 #8
0
 def buildLookup_(self, subtables):
     lookup = otTables.Lookup()
     lookup.LookupFlag = self.lookupflag
     lookup.LookupType = self.lookup_type
     lookup.SubTable = subtables
     lookup.SubTableCount = len(subtables)
     if self.markFilterSet is not None:
         lookup.MarkFilteringSet = self.markFilterSet
     return lookup
예제 #9
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
예제 #10
0
def parseLookup(lines, tableTag, font, lookupMap=None):
    line = lines.expect('lookup')
    _, name, typ = line
    log.debug("Parsing lookup type %s %s", typ, name)
    lookup = ot.Lookup()
    with lines.until('lookup end'):

        lookup.LookupFlag, filterset = parseLookupFlags(lines)
        if filterset is not None:
            lookup.MarkFilteringSet = filterset
        lookup.LookupType, parseLookupSubTable = {
            'GSUB': {
                'single': (0, parseSingleSubst),
                'multiple': (0, parseMultiple),
                'alternate': (0, parseAlternate),
                'ligature': (0, parseLigature),
                'context': (5, parseContextSubst),
                'chained': (6, parseChainedSubst),
                'reversechained': (8, parseReverseChainedSubst),
            },
            'GPOS': {
                'single': (0, parseSinglePos),
                'pair': (2, parsePair),
                'kernset': (2, parseKernset),
                'cursive': (0, parseCursive),
                'mark to base': (4, parseMarkToBase),
                'mark to ligature': (5, parseMarkToLigature),
                'mark to mark': (6, parseMarkToMark),
                'context': (7, parseContextPos),
                'chained': (8, parseChainedPos),
            },
        }[tableTag][typ]

        subtables = []

        while lines.peek():
            with lines.until(('% subtable', 'subtable end')):
                while lines.peek():
                    if lookup.LookupType is 0:
                        subtable = parseLookupSubTable(lines, font, lookupMap)
                        lookup.LookupType = subtable.LookupType
                    else:
                        subtable = ot.lookupTypes[tableTag][
                            lookup.LookupType]()
                        parseLookupSubTable(subtable, lines, font, lookupMap)
                    subtables.append(subtable)
            if lines.peek() and lines.peek()[0] in ('% subtable',
                                                    'subtable end'):
                next(lines)
    lines.expect('lookup end')

    lookup.SubTable = subtables
    lookup.SubTableCount = len(lookup.SubTable)
    if lookup.SubTableCount is 0:
        return None
    return lookup
예제 #11
0
 def build(self):
     lookup = otTables.Lookup()
     lookup.SubTable = []
     st = otTables.SingleSubst()
     st.mapping = self.mapping
     lookup.SubTable.append(st)
     lookup.LookupFlag = self.lookup_flag
     lookup.LookupType = self.lookup_type
     lookup.SubTableCount = len(lookup.SubTable)
     return lookup
예제 #12
0
 def build(self):
     lookup = otTables.Lookup()
     lookup.SubTable = []
     st = otTables.AlternateSubst()
     st.Format = 1
     st.alternates = self.alternates
     lookup.SubTable.append(st)
     lookup.LookupFlag = self.lookup_flag
     lookup.LookupType = self.lookup_type
     lookup.SubTableCount = len(lookup.SubTable)
     return lookup
예제 #13
0
def parseLookup(lines, tableTag, font, lookupMap=None):
	line = lines.expect('lookup')
	_, name, typ = line
	log.debug("Parsing lookup type %s %s", typ, name)
	lookup = ot.Lookup()
	lookup.LookupFlag,filterset = parseLookupFlags(lines)
	if filterset is not None:
		lookup.MarkFilteringSet = filterset
	lookup.LookupType, parseLookupSubTable = {
		'GSUB': {
			'single':	(1,	parseSingleSubst),
			'multiple':	(2,	parseMultiple),
			'alternate':	(3,	parseAlternate),
			'ligature':	(4,	parseLigature),
			'context':	(5,	parseContextSubst),
			'chained':	(6,	parseChainedSubst),
			'reversechained':(8,	parseReverseChainedSubst),
		},
		'GPOS': {
			'single':	(1,	parseSinglePos),
			'pair':		(2,	parsePair),
			'kernset':	(2,	parseKernset),
			'cursive':	(3,	parseCursive),
			'mark to base':	(4,	parseMarkToBase),
			'mark to ligature':(5,	parseMarkToLigature),
			'mark to mark':	(6,	parseMarkToMark),
			'context':	(7,	parseContextPos),
			'chained':	(8,	parseChainedPos),
		},
	}[tableTag][typ]

	with lines.until('lookup end'):
		subtables = []

		while lines.peek():
			with lines.until(('% subtable', 'subtable end')):
				while lines.peek():
					subtable = parseLookupSubTable(lines, font, lookupMap)
					assert lookup.LookupType == subtable.LookupType
					subtables.append(subtable)
			if lines.peeks()[0] in ('% subtable', 'subtable end'):
				next(lines)
	lines.expect('lookup end')

	lookup.SubTable = subtables
	lookup.SubTableCount = len(lookup.SubTable)
	if lookup.SubTableCount == 0:
		# Remove this return when following is fixed:
		# https://github.com/fonttools/fonttools/issues/789
		return None
	return lookup
예제 #14
0
 def build(self):
     lookup = otTables.Lookup()
     lookup.SubTable = []
     st = otTables.LigatureSubst()
     st.Format = 1
     st.ligatures = {}
     for components in sorted(self.ligatures.keys(), key=self.make_key):
         lig = otTables.Ligature()
         lig.Component = components
         lig.LigGlyph = self.ligatures[components]
         st.ligatures.setdefault(components[0], []).append(lig)
     lookup.SubTable.append(st)
     lookup.LookupFlag = self.lookup_flag
     lookup.LookupType = self.lookup_type
     lookup.SubTableCount = len(lookup.SubTable)
     return lookup
예제 #15
0
    def add_watermark(self, ttf):
        cmap = ttf.getBestCmap()
        gsub = ttf['GSUB'].table

        # Obtain Version string
        m = re.search('^Version (\d*)\.(\d*)', font_data.font_version(ttf))
        if not m:
            raise ValueError('The font does not have proper version string.')
        major = m.group(1)
        minor = m.group(2)
        # Replace the dot with space since NotoColorEmoji does not have glyph for dot.
        glyphs = [cmap[ord(x)] for x in '%s %s' % (major, minor)]

        # Update Glyph metrics
        ttf.getGlyphOrder().append(WATERMARK_NEW_GLYPH_ID)
        refGlyphId = cmap[WATERMARK_REF_CODE_POINT]
        ttf['hmtx'].metrics[WATERMARK_NEW_GLYPH_ID] = ttf['hmtx'].metrics[refGlyphId]
        ttf['vmtx'].metrics[WATERMARK_NEW_GLYPH_ID] = ttf['vmtx'].metrics[refGlyphId]

        # Add new Glyph to cmap
        font_data.add_to_cmap(ttf, { WATERMARK_NEW_CODE_POINT : WATERMARK_NEW_GLYPH_ID })

        # Add lookup table for the version string.
        lookups = gsub.LookupList.Lookup
        new_lookup = otTables.Lookup()
        new_lookup.LookupType = 2  # Multiple Substitution Subtable.
        new_lookup.LookupFlag = 0
        new_subtable = otTables.MultipleSubst()
        new_subtable.mapping = { WATERMARK_NEW_GLYPH_ID : tuple(glyphs) }
        new_lookup.SubTable = [ new_subtable ]
        new_lookup_index = len(lookups)
        lookups.append(new_lookup)

        # Add feature
        feature = next(x for x in gsub.FeatureList.FeatureRecord if x.FeatureTag == 'ccmp')
        if not feature:
            raise ValueError("Font doesn't contain ccmp feature.")

        feature.Feature.LookupListIndex.append(new_lookup_index)
예제 #16
0
    def init_gsub(self):
        """Call this if you are going to add ligatures to the font.  Creates a GSUB
    table if there isn't one already."""

        if hasattr(self, 'ligatures'):
            return
        font = self.font
        if 'GSUB' not in font:
            ligature_subst = otTables.LigatureSubst()
            ligature_subst.ligatures = {}

            lookup = otTables.Lookup()
            lookup.LookupType = 4
            lookup.LookupFlag = 0
            lookup.SubTableCount = 1
            lookup.SubTable = [ligature_subst]

            font['GSUB'] = add_emoji_gsub.create_simple_gsub([lookup])
        else:
            lookup = font['GSUB'].table.LookupList.Lookup[0]
            assert lookup.LookupType == 4
            assert lookup.LookupFlag == 0
        self.ligatures = lookup.SubTable[0].ligatures