示例#1
0
def buildPairPosClassesSubtable(pairs,
                                glyphMap,
                                valueFormat1=None,
                                valueFormat2=None):
    coverage = set()
    classDef1 = ClassDefBuilder(useClass0=True)
    classDef2 = ClassDefBuilder(useClass0=False)
    for gc1, gc2 in sorted(pairs):
        coverage.update(gc1)
        classDef1.add(gc1)
        classDef2.add(gc2)
    self = ot.PairPos()
    self.Format = 2
    self.ValueFormat1 = _getValueFormat(valueFormat1, pairs.values(), 0)
    self.ValueFormat2 = _getValueFormat(valueFormat2, pairs.values(), 1)
    self.Coverage = buildCoverage(coverage, glyphMap)
    self.ClassDef1 = classDef1.build()
    self.ClassDef2 = classDef2.build()
    classes1 = classDef1.classes()
    classes2 = classDef2.classes()
    self.Class1Record = []
    for c1 in classes1:
        rec1 = ot.Class1Record()
        rec1.Class2Record = []
        self.Class1Record.append(rec1)
        for c2 in classes2:
            rec2 = ot.Class2Record()
            rec2.Value1, rec2.Value2 = pairs.get((c1, c2), (None, None))
            rec1.Class2Record.append(rec2)
    self.Class1Count = len(self.Class1Record)
    self.Class2Count = len(classes2)
    return self
示例#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
示例#3
0
def _PairPosFormat2_align_matrices(self, lst, font, transparent=False):

    matrices = [l.Class1Record for l in lst]

    # Align first classes
    self.ClassDef1, classes = _ClassDef_merge_classify(
        [l.ClassDef1 for l in lst], [l.Coverage.glyphs for l in lst])
    self.Class1Count = len(classes)
    new_matrices = []
    for l, matrix in zip(lst, matrices):
        nullRow = None
        coverage = set(l.Coverage.glyphs)
        classDef1 = l.ClassDef1.classDefs
        class1Records = []
        for classSet in classes:
            exemplarGlyph = next(iter(classSet))
            if exemplarGlyph not in coverage:
                # Follow-up to e6125b353e1f54a0280ded5434b8e40d042de69f,
                # Fixes https://github.com/googlei18n/fontmake/issues/470
                # Again, revert 8d441779e5afc664960d848f62c7acdbfc71d7b9
                # when merger becomes selfless.
                nullRow = None
                if nullRow is None:
                    nullRow = ot.Class1Record()
                    class2records = nullRow.Class2Record = []
                    # TODO: When merger becomes selfless, revert e6125b353e1f54a0280ded5434b8e40d042de69f
                    for _ in range(l.Class2Count):
                        if transparent:
                            rec2 = None
                        else:
                            rec2 = ot.Class2Record()
                            rec2.Value1 = otBase.ValueRecord(
                                self.ValueFormat1
                            ) if self.ValueFormat1 else None
                            rec2.Value2 = otBase.ValueRecord(
                                self.ValueFormat2
                            ) if self.ValueFormat2 else None
                        class2records.append(rec2)
                rec1 = nullRow
            else:
                klass = classDef1.get(exemplarGlyph, 0)
                rec1 = matrix[klass]  # TODO handle out-of-range?
            class1Records.append(rec1)
        new_matrices.append(class1Records)
    matrices = new_matrices
    del new_matrices

    # Align second classes
    self.ClassDef2, classes = _ClassDef_merge_classify(
        [l.ClassDef2 for l in lst])
    self.Class2Count = len(classes)
    new_matrices = []
    for l, matrix in zip(lst, matrices):
        classDef2 = l.ClassDef2.classDefs
        class1Records = []
        for rec1old in matrix:
            oldClass2Records = rec1old.Class2Record
            rec1new = ot.Class1Record()
            class2Records = rec1new.Class2Record = []
            for classSet in classes:
                if not classSet:  # class=0
                    rec2 = oldClass2Records[0]
                else:
                    exemplarGlyph = next(iter(classSet))
                    klass = classDef2.get(exemplarGlyph, 0)
                    rec2 = oldClass2Records[klass]
                class2Records.append(copy.deepcopy(rec2))
            class1Records.append(rec1new)
        new_matrices.append(class1Records)
    matrices = new_matrices
    del new_matrices

    return matrices
示例#4
0
def parsePair(lines, font, _lookupMap=None):
	self = ot.PairPos()
	self.ValueFormat1 = self.ValueFormat2 = 0
	typ = lines.peeks()[0].split()[0].lower()
	if typ in ('left', 'right'):
		self.Format = 1
		values = {}
		for line in lines:
			assert len(line) == 4, line
			side = line[0].split()[0].lower()
			assert side in ('left', 'right'), side
			what = line[0][len(side):].title().replace(' ', '')
			mask = valueRecordFormatDict[what][0]
			glyph1, glyph2 = makeGlyphs(line[1:3])
			value = int(line[3])
			if not glyph1 in values: values[glyph1] = {}
			if not glyph2 in values[glyph1]: values[glyph1][glyph2] = (ValueRecord(),ValueRecord())
			rec2 = values[glyph1][glyph2]
			if side == 'left':
				self.ValueFormat1 |= mask
				vr = rec2[0]
			else:
				self.ValueFormat2 |= mask
				vr = rec2[1]
			assert not hasattr(vr, what), (vr, what)
			setattr(vr, what, value)
		self.Coverage = makeCoverage(set(values.keys()), font)
		self.PairSet = []
		for glyph1 in self.Coverage.glyphs:
			values1 = values[glyph1]
			pairset = ot.PairSet()
			records = pairset.PairValueRecord = []
			for glyph2 in sorted(values1.keys(), key=font.getGlyphID):
				values2 = values1[glyph2]
				pair = ot.PairValueRecord()
				pair.SecondGlyph = glyph2
				pair.Value1 = values2[0]
				pair.Value2 = values2[1] if self.ValueFormat2 else None
				records.append(pair)
			pairset.PairValueCount = len(pairset.PairValueRecord)
			self.PairSet.append(pairset)
		self.PairSetCount = len(self.PairSet)
	elif typ.endswith('class'):
		self.Format = 2
		classDefs = [None, None]
		while lines.peeks()[0].endswith("class definition begin"):
			typ = lines.peek()[0][:-len("class definition begin")].lower()
			idx,klass = {
				'first':	(0,ot.ClassDef1),
				'second':	(1,ot.ClassDef2),
			}[typ]
			assert classDefs[idx] is None
			classDefs[idx] = parseClassDef(lines, font, klass=klass)
		self.ClassDef1, self.ClassDef2 = classDefs
		self.Class1Count, self.Class2Count = (1+max(c.classDefs.values()) for c in classDefs)
		self.Class1Record = [ot.Class1Record() for i in range(self.Class1Count)]
		for rec1 in self.Class1Record:
			rec1.Class2Record = [ot.Class2Record() for j in range(self.Class2Count)]
			for rec2 in rec1.Class2Record:
				rec2.Value1 = ValueRecord()
				rec2.Value2 = ValueRecord()
		for line in lines:
			assert len(line) == 4, line
			side = line[0].split()[0].lower()
			assert side in ('left', 'right'), side
			what = line[0][len(side):].title().replace(' ', '')
			mask = valueRecordFormatDict[what][0]
			class1, class2, value = (int(x) for x in line[1:4])
			rec2 = self.Class1Record[class1].Class2Record[class2]
			if side == 'left':
				self.ValueFormat1 |= mask
				vr = rec2.Value1
			else:
				self.ValueFormat2 |= mask
				vr = rec2.Value2
			assert not hasattr(vr, what), (vr, what)
			setattr(vr, what, value)
		for rec1 in self.Class1Record:
			for rec2 in rec1.Class2Record:
				rec2.Value1 = ValueRecord(self.ValueFormat1, rec2.Value1)
				rec2.Value2 = ValueRecord(self.ValueFormat2, rec2.Value2) \
						if self.ValueFormat2 else None

		self.Coverage = makeCoverage(set(self.ClassDef1.classDefs.keys()), font)
	else:
		assert 0, typ
	return self
示例#5
0
def _PairPosFormat2_align_matrices(self, lst, font, transparent=False):

    matrices = [l.Class1Record for l in lst]

    # Align first classes
    self.ClassDef1, classes = _ClassDef_merge_classify(
        [l.ClassDef1 for l in lst], allGlyphs=set(self.Coverage.glyphs))
    _ClassDef_calculate_Format(self.ClassDef1, font)
    self.Class1Count = len(classes)
    new_matrices = []
    for l, matrix in zip(lst, matrices):
        nullRow = None
        coverage = set(l.Coverage.glyphs)
        classDef1 = l.ClassDef1.classDefs
        class1Records = []
        for classSet in classes:
            exemplarGlyph = next(iter(classSet))
            if exemplarGlyph not in coverage:
                if nullRow is None:
                    nullRow = ot.Class1Record()
                    class2records = nullRow.Class2Record = []
                    # TODO: When merger becomes selfless, revert e6125b353e1f54a0280ded5434b8e40d042de69f
                    for _ in range(l.Class2Count):
                        if transparent:
                            rec2 = None
                        else:
                            rec2 = ot.Class2Record()
                            rec2.Value1 = otBase.ValueRecord(
                                self.ValueFormat1
                            ) if self.ValueFormat1 else None
                            rec2.Value2 = otBase.ValueRecord(
                                self.ValueFormat2
                            ) if self.ValueFormat2 else None
                        class2records.append(rec2)
                rec1 = nullRow
            else:
                klass = classDef1.get(exemplarGlyph, 0)
                rec1 = matrix[klass]  # TODO handle out-of-range?
            class1Records.append(rec1)
        new_matrices.append(class1Records)
    matrices = new_matrices
    del new_matrices

    # Align second classes
    self.ClassDef2, classes = _ClassDef_merge_classify(
        [l.ClassDef2 for l in lst])
    _ClassDef_calculate_Format(self.ClassDef2, font)
    self.Class2Count = len(classes)
    new_matrices = []
    for l, matrix in zip(lst, matrices):
        classDef2 = l.ClassDef2.classDefs
        class1Records = []
        for rec1old in matrix:
            oldClass2Records = rec1old.Class2Record
            rec1new = ot.Class1Record()
            class2Records = rec1new.Class2Record = []
            for classSet in classes:
                if not classSet:  # class=0
                    rec2 = oldClass2Records[0]
                else:
                    exemplarGlyph = next(iter(classSet))
                    klass = classDef2.get(exemplarGlyph, 0)
                    rec2 = oldClass2Records[klass]
                class2Records.append(rec2)
            class1Records.append(rec1new)
        new_matrices.append(class1Records)
    matrices = new_matrices
    del new_matrices

    return matrices
示例#6
0
def _PairPosFormat2_merge(self, lst, merger):

	merger.mergeObjects(self, lst,
			    exclude=('Coverage',
				     'ClassDef1', 'Class1Count',
				     'ClassDef2', 'Class2Count',
				     'Class1Record'))

	# Align coverages
	glyphs, _ = _merge_GlyphOrders(merger.font,
				       [v.Coverage.glyphs for v in lst])
	self.Coverage.glyphs = glyphs
	glyphSet = set(glyphs)

	# Currently, if the coverage of PairPosFormat2 subtables are different,
	# we do NOT bother walking down the subtable list when filling in new
	# rows for alignment.  As such, this is only correct if current subtable
	# is the last subtable in the lookup.  Ensure that.
	#
	# Note that our canonicalization process merges some PairPosFormat2's,
	# so in reality this might not be common.
	#
	# TODO: Remove this requirement
	for l,subtables in zip(lst,merger.lookup_subtables):
		if l.Coverage.glyphs != glyphs:
			assert l == subtables[-1]

	matrices = [l.Class1Record for l in lst]

	# Align first classes
	self.ClassDef1, classes = _ClassDef_merge_classify([l.ClassDef1 for l in lst], allGlyphs=glyphSet)
	_ClassDef_calculate_Format(self.ClassDef1, merger.font)
	self.Class1Count = len(classes)
	new_matrices = []
	for l,matrix in zip(lst, matrices):
		nullRow = None
		coverage = set(l.Coverage.glyphs)
		classDef1 = l.ClassDef1.classDefs
		class1Records = []
		for classSet in classes:
			exemplarGlyph = next(iter(classSet))
			if exemplarGlyph not in coverage:
				if nullRow is None:
					nullRow = ot.Class1Record()
					class2records = nullRow.Class2Record = []
					# TODO: When merger becomes selfless, revert e6125b353e1f54a0280ded5434b8e40d042de69f
					for _ in range(l.Class2Count):
						rec2 = ot.Class2Record()
						rec2.Value1 = otBase.ValueRecord(l.ValueFormat1) if l.ValueFormat1 else None
						rec2.Value2 = otBase.ValueRecord(l.ValueFormat2) if l.ValueFormat2 else None
						class2records.append(rec2)
				rec1 = nullRow
			else:
				klass = classDef1.get(exemplarGlyph, 0)
				rec1 = matrix[klass] # TODO handle out-of-range?
			class1Records.append(rec1)
		new_matrices.append(class1Records)
	matrices = new_matrices
	del new_matrices

	# Align second classes
	self.ClassDef2, classes = _ClassDef_merge_classify([l.ClassDef2 for l in lst])
	_ClassDef_calculate_Format(self.ClassDef2, merger.font)
	self.Class2Count = len(classes)
	new_matrices = []
	for l,matrix in zip(lst, matrices):
		classDef2 = l.ClassDef2.classDefs
		class1Records = []
		for rec1old in matrix:
			oldClass2Records = rec1old.Class2Record
			rec1new = ot.Class1Record()
			class2Records = rec1new.Class2Record = []
			for classSet in classes:
				if not classSet: # class=0
					rec2 = oldClass2Records[0]
				else:
					exemplarGlyph = next(iter(classSet))
					klass = classDef2.get(exemplarGlyph, 0)
					rec2 = oldClass2Records[klass]
				class2Records.append(rec2)
			class1Records.append(rec1new)
		new_matrices.append(class1Records)
	matrices = new_matrices
	del new_matrices

	self.Class1Record = list(matrices[0]) # TODO move merger to be selfless
	merger.mergeLists(self.Class1Record, matrices)
示例#7
0
def _PairPosFormat2_merge(self, lst, merger):
    merger.mergeObjects(self,
                        lst,
                        exclude=('Coverage', 'ClassDef1', 'Class1Count',
                                 'ClassDef2', 'Class2Count', 'Class1Record'))

    # Align coverages
    glyphs, _ = _merge_GlyphOrders(merger.font,
                                   [v.Coverage.glyphs for v in lst])
    self.Coverage.glyphs = glyphs
    glyphSet = set(glyphs)

    # Currently, if the coverage of PairPosFormat2 subtables are different,
    # we do NOT bother walking down the subtable list when filling in new
    # rows for alignment.  As such, this is only correct if current subtable
    # is the last subtable in the lookup.  Ensure that.
    # TODO: Remove this requirement
    for l, lookup in zip(lst, merger.lookups):
        if l.Coverage.glyphs != glyphs:
            assert l == lookup.SubTable[-1]

    matrices = [l.Class1Record for l in lst]

    # Align first classes
    self.ClassDef1, classes = _ClassDef_merge_classify(
        [l.ClassDef1 for l in lst], allGlyphs=glyphSet)
    self.Class1Count = len(classes)
    new_matrices = []
    for l, matrix in zip(lst, matrices):
        nullRow = None
        coverage = set(l.Coverage.glyphs)
        classDef1 = l.ClassDef1.classDefs
        class1Records = []
        for classSet in classes:
            exemplarGlyph = next(iter(classSet))
            if exemplarGlyph not in coverage:
                if nullRow is None:
                    rec2 = ot.Class2Record()
                    rec2.Value1 = otBase.ValueRecord(
                        l.ValueFormat1) if l.ValueFormat1 else None
                    rec2.Value2 = otBase.ValueRecord(
                        l.ValueFormat2) if l.ValueFormat2 else None
                    nullRow = ot.Class1Record()
                    nullRow.Class2Record = [rec2] * l.Class2Count
                rec1 = nullRow
            else:
                klass = classDef1.get(exemplarGlyph, 0)
                rec1 = matrix[klass]  # TODO handle out-of-range?
            class1Records.append(rec1)
        new_matrices.append(class1Records)
    matrices = new_matrices
    del new_matrices

    # Align second classes
    self.ClassDef2, classes = _ClassDef_merge_classify(
        [l.ClassDef2 for l in lst])
    self.Class2Count = len(classes)
    new_matrices = []
    for l, matrix in zip(lst, matrices):
        classDef2 = l.ClassDef2.classDefs
        class1Records = []
        for rec1old in matrix:
            oldClass2Records = rec1old.Class2Record
            rec1new = ot.Class1Record()
            class2Records = rec1new.Class2Record = []
            for classSet in classes:
                if not classSet:  # class=0
                    rec2 = oldClass2Records[0]
                else:
                    exemplarGlyph = next(iter(classSet))
                    klass = classDef2.get(exemplarGlyph, 0)
                    rec2 = oldClass2Records[klass]
                class2Records.append(rec2)
            class1Records.append(rec1new)
        new_matrices.append(class1Records)
    matrices = new_matrices
    del new_matrices

    self.Class1Record = list(matrices[0])  # TODO move merger to be selfless
    merger.mergeLists(self.Class1Record, matrices)