Ejemplo n.º 1
0
def _Lookup_PairPosFormat2_subtables_recombine(a, b, font):
    """Combine two subtables that have the same general structure already."""
    self = ot.PairPos()
    self.Format = 2
    self.Coverage = ot.Coverage()
    self.Coverage.Format = 1
    glyphs, _ = _merge_GlyphOrders(font, [v.Coverage.glyphs for v in (a, b)])

    self.Coverage.glyphs = glyphs
    self.Class1Count = a.Class1Count + b.Class1Count
    self.ClassDef1 = ot.ClassDef()

    classDefs = self.ClassDef1.classDefs = {}
    offset = a.Class1Count
    # First subtable overrides any possible shared glyph, so add b first.
    sets = _ClassDef_invert(b.ClassDef1, allGlyphs=b.Coverage.glyphs)
    for i, s in enumerate(sets):
        for g in s:
            classDefs[g] = i + offset
    sets = _ClassDef_invert(a.ClassDef1, allGlyphs=a.Coverage.glyphs)
    assert len(sets) <= offset
    for i, s in enumerate(sets):
        for g in s:
            classDefs[g] = i

    records = self.Class1Record = []
    assert a.Class1Count == len(a.Class1Record)
    assert b.Class1Count == len(b.Class1Record)
    records.extend(a.Class1Record)
    records.extend(b.Class1Record)

    for name in ('Class2Count', 'ClassDef2', 'ValueFormat1', 'ValueFormat2'):
        setattr(self, name, getattr(a, name))

    return self
Ejemplo n.º 2
0
def _Lookup_PairPosFormat2_subtables_flatten(lst, font):
    assert allEqual([l.ValueFormat2 == 0 for l in lst
                     if l.Class1Record]), "Report bug against fonttools."

    self = ot.PairPos()
    self.Format = 2
    self.Coverage = ot.Coverage()
    self.ValueFormat1 = reduce(int.__or__, [l.ValueFormat1 for l in lst], 0)
    self.ValueFormat2 = reduce(int.__or__, [l.ValueFormat2 for l in lst], 0)

    # Align them
    glyphs, _ = _merge_GlyphOrders(font, [v.Coverage.glyphs for v in lst])
    self.Coverage.glyphs = glyphs

    matrices = _PairPosFormat2_align_matrices(self,
                                              lst,
                                              font,
                                              transparent=True)

    matrix = self.Class1Record = []
    for rows in zip(*matrices):
        row = ot.Class1Record()
        matrix.append(row)
        row.Class2Record = []
        row = row.Class2Record
        for cols in zip(*list(r.Class2Record for r in rows)):
            col = next(iter(c for c in cols if c is not None))
            row.append(col)

    return self
Ejemplo n.º 3
0
    def makeGDEF(self):
        gdef = otTables.GDEF()
        gdef.Version = 1.0
        gdef.GlyphClassDef = otTables.GlyphClassDef()

        inferredGlyphClass = {}
        for lookup in self.lookups_:
            inferredGlyphClass.update(lookup.inferGlyphClasses())

        marks = {}  # glyph --> markClass
        for markClass in self.parseTree.markClasses.values():
            for markClassDef in markClass.definitions:
                for glyph in markClassDef.glyphSet():
                    other = marks.get(glyph)
                    if other not in (None, markClass):
                        name1, name2 = sorted([markClass.name, other.name])
                        raise FeatureLibError(
                            'Glyph %s cannot be both in '
                            'markClass @%s and @%s' % (glyph, name1, name2),
                            markClassDef.location)
                    marks[glyph] = markClass
                    inferredGlyphClass[glyph] = 3

        gdef.GlyphClassDef.classDefs = inferredGlyphClass
        gdef.AttachList = None
        gdef.LigCaretList = None

        markAttachClass = {g: c for g, (c, _) in self.markAttach_.items()}
        if markAttachClass:
            gdef.MarkAttachClassDef = otTables.MarkAttachClassDef()
            gdef.MarkAttachClassDef.classDefs = markAttachClass
        else:
            gdef.MarkAttachClassDef = None

        if self.markFilterSets_:
            gdef.Version = 0x00010002
            m = gdef.MarkGlyphSetsDef = otTables.MarkGlyphSetsDef()
            m.MarkSetTableFormat = 1
            m.MarkSetCount = len(self.markFilterSets_)
            m.Coverage = []
            filterSets = [(id, glyphs)
                          for (glyphs, id) in self.markFilterSets_.items()]
            for i, glyphs in sorted(filterSets):
                coverage = otTables.Coverage()
                coverage.glyphs = sorted(glyphs, key=self.font.getGlyphID)
                m.Coverage.append(coverage)

        if (len(gdef.GlyphClassDef.classDefs) == 0
                and gdef.MarkAttachClassDef is None):
            return None
        result = getTableClass("GDEF")()
        result.table = gdef
        return result
Ejemplo n.º 4
0
def _Lookup_PairPosFormat1_subtables_merge_overlay(lst, font):
	self = ot.PairPos()
	self.Format = 1
	self.Coverage = ot.Coverage()
	self.Coverage.Format = 1
	self.ValueFormat1 = reduce(int.__or__, [l.ValueFormat1 for l in lst], 0)
	self.ValueFormat2 = reduce(int.__or__, [l.ValueFormat2 for l in lst], 0)

	# Align them
	glyphs, padded = _merge_GlyphOrders(font,
					    [v.Coverage.glyphs for v in lst],
					    [v.PairSet for v in lst])

	self.Coverage.glyphs = glyphs
	self.PairSet = [_PairSet_merge_overlay([v for v in values if v is not None], font)
		        for values in zip(*padded)]
	self.PairSetCount = len(self.PairSet)
	return self
Ejemplo n.º 5
0
def _Lookup_PairPosFormat1_subtables_flatten(lst, font):
	assert allEqual([l.ValueFormat2 == 0 for l in lst if l.PairSet]), "Report bug against fonttools."

	self = ot.PairPos()
	self.Format = 1
	self.Coverage = ot.Coverage()
	self.ValueFormat1 = reduce(int.__or__, [l.ValueFormat1 for l in lst], 0)
	self.ValueFormat2 = reduce(int.__or__, [l.ValueFormat2 for l in lst], 0)

	# Align them
	glyphs, padded = _merge_GlyphOrders(font,
					    [v.Coverage.glyphs for v in lst],
					    [v.PairSet for v in lst])

	self.Coverage.glyphs = glyphs
	self.PairSet = [_PairSet_flatten([v for v in values if v is not None], font)
		        for values in zip(*padded)]
	self.PairSetCount = len(self.PairSet)
	return self
Ejemplo n.º 6
0
def _PairSet_flatten(lst, font):
    self = ot.PairSet()
    self.Coverage = ot.Coverage()

    # Align them
    glyphs, padded = _merge_GlyphOrders(
        font, [[v.SecondGlyph for v in vs.PairValueRecord] for vs in lst],
        [vs.PairValueRecord for vs in lst])

    self.Coverage.glyphs = glyphs
    self.PairValueRecord = pvrs = []
    for values in zip(*padded):
        for v in values:
            if v is not None:
                pvrs.append(v)
                break
        else:
            assert False
    self.PairValueCount = len(self.PairValueRecord)

    return self
Ejemplo n.º 7
0
def _Lookup_SinglePos_subtables_flatten(lst, font, min_inclusive_rec_format):
    glyphs, _ = _merge_GlyphOrders(font, [v.Coverage.glyphs for v in lst],
                                   None)
    num_glyphs = len(glyphs)
    new = ot.SinglePos()
    new.Format = 2
    new.ValueFormat = min_inclusive_rec_format
    new.Coverage = ot.Coverage()
    new.Coverage.glyphs = glyphs
    new.ValueCount = num_glyphs
    new.Value = [None] * num_glyphs
    for singlePos in lst:
        if singlePos.Format == 1:
            val_rec = singlePos.Value
            for gname in singlePos.Coverage.glyphs:
                i = glyphs.index(gname)
                new.Value[i] = copy.deepcopy(val_rec)
        elif singlePos.Format == 2:
            for j, gname in enumerate(singlePos.Coverage.glyphs):
                val_rec = singlePos.Value[j]
                i = glyphs.index(gname)
                new.Value[i] = copy.deepcopy(val_rec)
    return [new]
Ejemplo n.º 8
0
    def build(self):
        subtables = []

        # If multiple glyphs have the same ValueRecord, they can go into
        # the same subtable which saves space. Therefore, we first build
        # a reverse mapping from ValueRecord to glyph coverage.
        values = {}
        for glyph, valuerecord in self.mapping.items():
            values.setdefault(valuerecord, []).append(glyph)

        # For compliance with the OpenType specification,
        # we sort the glyph coverage by glyph ID.
        for glyphs in values.values():
            glyphs.sort(key=self.font.getGlyphID)

        # Make a list of (glyphs, (otBase.ValueRecord, int valueFormat)).
        # Glyphs with the same otBase.ValueRecord are grouped into one item.
        values = [(glyphs, makeOpenTypeValueRecord(valrec))
                  for valrec, glyphs in values.items()]

        # Find out which glyphs should be encoded as SinglePos format 2.
        # Format 2 is more compact than format 1 when multiple glyphs
        # have different values but share the same integer valueFormat.
        format2 = {}  # valueFormat --> [(glyph, value), (glyph, value), ...]
        for glyphs, (value, valueFormat) in values:
            if len(glyphs) == 1:
                glyph = glyphs[0]
                format2.setdefault(valueFormat, []).append((glyph, value))

        # Only use format 2 if multiple glyphs share the same valueFormat.
        # Otherwise, format 1 is more compact.
        format2 = [(valueFormat, valueList)
                   for valueFormat, valueList in format2.items()
                   if len(valueList) > 1]
        format2.sort()
        format2Glyphs = set()  # {"A", "B", "C"}
        for _, valueList in format2:
            for (glyph, _) in valueList:
                format2Glyphs.add(glyph)
        for valueFormat, valueList in format2:
            valueList.sort(key=lambda x: self.font.getGlyphID(x[0]))
            st = otTables.SinglePos()
            subtables.append(st)
            st.Format = 2
            st.ValueFormat = valueFormat
            st.Coverage = otTables.Coverage()
            st.Coverage.glyphs = [glyph for glyph, _value in valueList]
            st.ValueCount = len(valueList)
            st.Value = [value for _glyph, value in valueList]

        # To make the ordering of our subtables deterministic,
        # we sort subtables by the first glyph ID in their coverage.
        # Not doing this would be OK for OpenType, but testing the
        # compiler would be harder with non-deterministic output.
        values.sort(key=lambda x: self.font.getGlyphID(x[0][0]))

        for glyphs, (value, valueFormat) in values:
            if len(glyphs) == 1 and glyphs[0] in format2Glyphs:
                continue  # already emitted as part of a format 2 subtable
            st = otTables.SinglePos()
            subtables.append(st)
            st.Format = 1
            st.Coverage = self.buildCoverage_(glyphs)
            st.Value, st.ValueFormat = value, valueFormat

        return self.buildLookup_(subtables)
Ejemplo n.º 9
0
def makeCoverage(glyphs):
    coverage = otTables.Coverage()
    coverage.glyphs = glyphs
    return coverage
Ejemplo n.º 10
0
def buildCoverage(glyphs, glyphMap):
    if not glyphs:
        return None
    self = ot.Coverage()
    self.glyphs = sorted(glyphs, key=glyphMap.__getitem__)
    return self
Ejemplo n.º 11
0
 def _coverage(glyphs):
     c = otTables.Coverage()
     c.glyphs = glyphs
     return c