コード例 #1
0
	def test_decompileCoord_roundTrip(self):
		# Make sure we are not affected by https://github.com/behdad/fonttools/issues/286
		data = deHexStr("7F B9 80 35")
		values, _ = TupleVariation.decompileCoord_(["wght", "wdth"], data, 0)
		axisValues = {axis:(val, val, val) for axis, val in  values.items()}
		var = TupleVariation(axisValues, [None] * 4)
		self.assertEqual("7F B9 80 35", hexencode(var.compileCoord(["wght", "wdth"])))
コード例 #2
0
	def test_fromXML_badDeltaFormat(self):
		g = TupleVariation({}, [])
		with CapturingLogHandler(log, "WARNING") as captor:
			for name, attrs, content in parseXML('<delta a="1" b="2"/>'):
				g.fromXML(name, attrs, content)
		self.assertIn("bad delta format: a, b",
		              [r.msg for r in captor.records])
コード例 #3
0
	def test_decompilePoints_roundTrip(self):
		numPointsInGlyph = 500  # greater than 255, so we also exercise code path for 16-bit encoding
		compile = lambda points: TupleVariation.compilePoints(points, numPointsInGlyph)
		decompile = lambda data: set(TupleVariation.decompilePoints_(numPointsInGlyph, data, 0, "gvar")[0])
		for i in range(50):
			points = set(random.sample(range(numPointsInGlyph), 30))
			self.assertSetEqual(points, decompile(compile(points)),
					    "failed round-trip decompile/compilePoints; points=%s" % points)
		allPoints = set(range(numPointsInGlyph))
		self.assertSetEqual(allPoints, decompile(compile(allPoints)))
コード例 #4
0
	def test_toXML_allDeltasNone(self):
		writer = XMLWriter(BytesIO())
		axes = {"wght":(0.0, 1.0, 1.0)}
		g = TupleVariation(axes, [None] * 5)
		g.toXML(writer, ["wght", "wdth"])
		self.assertEqual([
			'<tuple>',
			  '<coord axis="wght" value="1.0"/>',
			  '<!-- no deltas -->',
			'</tuple>'
		], TupleVariationTest.xml_lines(writer))
コード例 #5
0
	def test_fromXML_constants(self):
		g = TupleVariation({}, [None] * 4)
		for name, attrs, content in parseXML(
				'<coord axis="wdth" min="0.3" value="0.4" max="0.5"/>'
				'<coord axis="wght" value="1.0"/>'
				'<coord axis="opsz" value="-0.7"/>'
				'<delta cvt="1" value="42"/>'
				'<delta cvt="2" value="-23"/>'):
			g.fromXML(name, attrs, content)
		self.assertEqual(AXES, g.axes)
		self.assertEqual([None, 42, -23, None], g.coordinates)
コード例 #6
0
	def test_fromXML_points(self):
		g = TupleVariation({}, [None] * 4)
		for name, attrs, content in parseXML(
				'<coord axis="wdth" min="0.3" value="0.4" max="0.5"/>'
				'<coord axis="wght" value="1.0"/>'
				'<coord axis="opsz" value="-0.7"/>'
				'<delta pt="1" x="33" y="44"/>'
				'<delta pt="2" x="-2" y="170"/>'):
			g.fromXML(name, attrs, content)
		self.assertEqual(AXES, g.axes)
		self.assertEqual([None, (33, 44), (-2, 170), None], g.coordinates)
コード例 #7
0
	def test_compile_embeddedPeak_nonIntermediate_sharedConstants(self):
		var = TupleVariation(
			{"wght": (0.0, 0.5, 0.5), "wdth": (0.0, 0.8, 0.8)},
			[3, 1, 4])
		tup, deltas = var.compile(axisTags=["wght", "wdth"],
		                          sharedCoordIndices={}, sharedPoints={0, 1, 2})
		# len(deltas)=4; flags=EMBEDDED_PEAK_TUPLE
		# embeddedPeak=[(0.5, 0.8)]; intermediateCoord=[]
		self.assertEqual("00 04 80 00 20 00 33 33", hexencode(tup))
		self.assertEqual("02 03 01 04",     # delta: [3, 1, 4]
						 hexencode(deltas))
コード例 #8
0
	def test_toXML_badDeltaFormat(self):
		writer = XMLWriter(BytesIO())
		g = TupleVariation(AXES, ["String"])
		with CapturingLogHandler(log, "ERROR") as captor:
			g.toXML(writer, ["wdth"])
		self.assertIn("bad delta format", [r.msg for r in captor.records])
		self.assertEqual([
			'<tuple>',
			  '<coord axis="wdth" max="0.5" min="0.3" value="0.4"/>',
			  '<!-- bad delta #0 -->',
			'</tuple>',
		], TupleVariationTest.xml_lines(writer))
コード例 #9
0
ファイル: _c_v_a_r.py プロジェクト: anthrotype/fonttools
 def fromXML(self, name, attrs, content, ttFont):
     if name == "version":
         self.majorVersion = int(attrs.get("major", "1"))
         self.minorVersion = int(attrs.get("minor", "0"))
     elif name == "tuple":
         valueCount = len(ttFont["cvt "].values)
         var = TupleVariation({}, [None] * valueCount)
         self.variations.append(var)
         for tupleElement in content:
             if isinstance(tupleElement, tuple):
                 tupleName, tupleAttrs, tupleContent = tupleElement
                 var.fromXML(tupleName, tupleAttrs, tupleContent)
コード例 #10
0
ファイル: __init__.py プロジェクト: robmck-ms/fonttools
def _add_gvar(font, model, master_ttfs, tolerance=0.5, optimize=True):

	assert tolerance >= 0

	log.info("Generating gvar")
	assert "gvar" not in font
	gvar = font["gvar"] = newTable('gvar')
	gvar.version = 1
	gvar.reserved = 0
	gvar.variations = {}

	for glyph in font.getGlyphOrder():

		allData = [_GetCoordinates(m, glyph) for m in master_ttfs]
		allCoords = [d[0] for d in allData]
		allControls = [d[1] for d in allData]
		control = allControls[0]
		if (any(c != control for c in allControls)):
			log.warning("glyph %s has incompatible masters; skipping" % glyph)
			continue
		del allControls

		# Update gvar
		gvar.variations[glyph] = []
		deltas = model.getDeltas(allCoords)
		supports = model.supports
		assert len(deltas) == len(supports)

		# Prepare for IUP optimization
		origCoords = deltas[0]
		endPts = control[1] if control[0] >= 1 else list(range(len(control[1])))

		for i,(delta,support) in enumerate(zip(deltas[1:], supports[1:])):
			if all(abs(v) <= tolerance for v in delta.array):
				continue
			var = TupleVariation(support, delta)
			if optimize:
				delta_opt = iup_delta_optimize(delta, origCoords, endPts, tolerance=tolerance)

				if None in delta_opt:
					# Use "optimized" version only if smaller...
					var_opt = TupleVariation(support, delta_opt)

					axis_tags = sorted(support.keys()) # Shouldn't matter that this is different from fvar...?
					tupleData, auxData, _ = var.compile(axis_tags, [], None)
					unoptimized_len = len(tupleData) + len(auxData)
					tupleData, auxData, _ = var_opt.compile(axis_tags, [], None)
					optimized_len = len(tupleData) + len(auxData)

					if optimized_len < unoptimized_len:
						var = var_opt

			gvar.variations[glyph].append(var)
コード例 #11
0
	def test_compile_embeddedPeak_nonIntermediate_privateConstants(self):
		var = TupleVariation(
			{"wght": (0.0, 0.5, 0.5), "wdth": (0.0, 0.8, 0.8)},
			[7, 8, 9])
		tup, deltas = var.compile(
			axisTags=["wght", "wdth"], sharedCoordIndices={}, sharedPoints=None)
		# len(deltas)=5; flags=PRIVATE_POINT_NUMBERS|EMBEDDED_PEAK_TUPLE
		# embeddedPeak=[(0.5, 0.8)]; intermediateCoord=[]
		self.assertEqual("00 05 A0 00 20 00 33 33", hexencode(tup))
		self.assertEqual("00 "           # all points in glyph
		                 "02 07 08 09",  # delta: [7, 8, 9]
		                 hexencode(deltas))
コード例 #12
0
	def test_compile_embeddedPeak_nonIntermediate_sharedPoints(self):
		var = TupleVariation(
			{"wght": (0.0, 0.5, 0.5), "wdth": (0.0, 0.8, 0.8)},
			[(7,4), (8,5), (9,6)])
		tup, deltas = var.compile(axisTags=["wght", "wdth"],
		                          sharedCoordIndices={}, sharedPoints={0, 1, 2})
		# len(deltas)=8; flags=EMBEDDED_PEAK_TUPLE
		# embeddedPeak=[(0.5, 0.8)]; intermediateCoord=[]
		self.assertEqual("00 08 80 00 20 00 33 33", hexencode(tup))
		self.assertEqual("02 07 08 09 "     # deltaX: [7, 8, 9]
						 "02 04 05 06",     # deltaY: [4, 5, 6]
						 hexencode(deltas))
コード例 #13
0
	def test_compile_sharedPeaks_intermediate_sharedPoints(self):
		var = TupleVariation(
			{"wght": (0.3, 0.5, 0.7), "wdth": (0.1, 0.8, 0.9)},
			[(7,4), (8,5), (9,6)])
		axisTags = ["wght", "wdth"]
		sharedPeakIndices = { var.compileCoord(axisTags): 0x77 }
		tup, deltas = var.compile(axisTags, sharedPeakIndices,
		                          sharedPoints={0,1,2})
		# len(deltas)=8; flags=INTERMEDIATE_REGION; tupleIndex=0x77
		# embeddedPeak=[]; intermediateCoord=[(0.3, 0.1), (0.7, 0.9)]
		self.assertEqual("00 08 40 77 13 33 06 66 2C CD 39 9A", hexencode(tup))
		self.assertEqual("02 07 08 09 "     # deltaX: [7, 8, 9]
						 "02 04 05 06",     # deltaY: [4, 5, 6]
						 hexencode(deltas))
コード例 #14
0
	def test_compile_sharedPeaks_nonIntermediate_sharedPoints(self):
		var = TupleVariation(
			{"wght": (0.0, 0.5, 0.5), "wdth": (0.0, 0.8, 0.8)},
			[(7,4), (8,5), (9,6)])
		axisTags = ["wght", "wdth"]
		sharedPeakIndices = { var.compileCoord(axisTags): 0x77 }
		tup, deltas = var.compile(axisTags, sharedPeakIndices,
		                          sharedPoints={0,1,2})
		# len(deltas)=8; flags=None; tupleIndex=0x77
		# embeddedPeaks=[]; intermediateCoord=[]
		self.assertEqual("00 08 00 77", hexencode(tup))
		self.assertEqual("02 07 08 09 "     # deltaX: [7, 8, 9]
						 "02 04 05 06",     # deltaY: [4, 5, 6]
						 hexencode(deltas))
コード例 #15
0
	def test_compile_sharedPeaks_nonIntermediate_privatePoints(self):
		var = TupleVariation(
			{"wght": (0.0, 0.5, 0.5), "wdth": (0.0, 0.8, 0.8)},
			[(7,4), (8,5), (9,6)])
		axisTags = ["wght", "wdth"]
		sharedPeakIndices = { var.compileCoord(axisTags): 0x77 }
		tup, deltas, _ = var.compile(axisTags, sharedPeakIndices,
		                          sharedPoints=None)
		# len(deltas)=9; flags=PRIVATE_POINT_NUMBERS; tupleIndex=0x77
		# embeddedPeak=[]; intermediateCoord=[]
		self.assertEqual("00 09 20 77", hexencode(tup))
		self.assertEqual("00 "              # all points in glyph
						 "02 07 08 09 "     # deltaX: [7, 8, 9]
						 "02 04 05 06",     # deltaY: [4, 5, 6]
						 hexencode(deltas))
コード例 #16
0
	def test_toXML_constants(self):
		writer = XMLWriter(BytesIO())
		g = TupleVariation(AXES, [42, None, 23, 0, -17, None])
		g.toXML(writer, ["wdth", "wght", "opsz"])
		self.assertEqual([
			'<tuple>',
			  '<coord axis="wdth" max="0.5" min="0.3" value="0.4"/>',
			  '<coord axis="wght" value="1.0"/>',
			  '<coord axis="opsz" value="-0.7"/>',
			  '<delta cvt="0" value="42"/>',
			  '<delta cvt="2" value="23"/>',
			  '<delta cvt="3" value="0"/>',
			  '<delta cvt="4" value="-17"/>',
			'</tuple>'
		], TupleVariationTest.xml_lines(writer))
コード例 #17
0
	def test_compile_embeddedPeak_intermediate_privateConstants(self):
		var = TupleVariation(
			{"wght": (0.4, 0.5, 0.6), "wdth": (0.7, 0.8, 0.9)},
			[7, 8, 9])
		tup, deltas = var.compile(
			axisTags = ["wght", "wdth"],
			sharedCoordIndices={}, sharedPoints=None)
		# len(deltas)=5;
		# flags=PRIVATE_POINT_NUMBERS|INTERMEDIATE_REGION|EMBEDDED_PEAK_TUPLE
		# embeddedPeak=(0.5, 0.8); intermediateCoord=[(0.4, 0.7), (0.6, 0.9)]
		self.assertEqual("00 05 E0 00 20 00 33 33 19 9A 2C CD 26 66 39 9A",
		                 hexencode(tup))
		self.assertEqual("00 "             # all points in glyph
		                 "02 07 08 09",    # delta: [7, 8, 9]
		                 hexencode(deltas))
コード例 #18
0
	def test_toXML_points(self):
		writer = XMLWriter(BytesIO())
		g = TupleVariation(AXES, [(9,8), None, (7,6), (0,0), (-1,-2), None])
		g.toXML(writer, ["wdth", "wght", "opsz"])
		self.assertEqual([
			'<tuple>',
			  '<coord axis="wdth" max="0.5" min="0.3" value="0.4"/>',
			  '<coord axis="wght" value="1.0"/>',
			  '<coord axis="opsz" value="-0.7"/>',
			  '<delta pt="0" x="9" y="8"/>',
			  '<delta pt="2" x="7" y="6"/>',
			  '<delta pt="3" x="0" y="0"/>',
			  '<delta pt="4" x="-1" y="-2"/>',
			'</tuple>'
		], TupleVariationTest.xml_lines(writer))
コード例 #19
0
	def test_decompileDeltas_roundTrip(self):
		numDeltas = 30
		compile = TupleVariation.compileDeltaValues_
		decompile = lambda data: TupleVariation.decompileDeltas_(numDeltas, data, 0)[0]
		for i in range(50):
			deltas = random.sample(range(-128, 127), 10)
			deltas.extend(random.sample(range(-32768, 32767), 10))
			deltas.extend([0] * 10)
			random.shuffle(deltas)
			self.assertListEqual(deltas, decompile(compile(deltas)))
コード例 #20
0
	def test_compileDeltaValues(self):
		compileDeltaValues = lambda values: hexencode(TupleVariation.compileDeltaValues_(values))
		# zeroes
		self.assertEqual("80", compileDeltaValues([0]))
		self.assertEqual("BF", compileDeltaValues([0] * 64))
		self.assertEqual("BF 80", compileDeltaValues([0] * 65))
		self.assertEqual("BF A3", compileDeltaValues([0] * 100))
		self.assertEqual("BF BF BF BF", compileDeltaValues([0] * 256))
		# bytes
		self.assertEqual("00 01", compileDeltaValues([1]))
		self.assertEqual("06 01 02 03 7F 80 FF FE", compileDeltaValues([1, 2, 3, 127, -128, -1, -2]))
		self.assertEqual("3F" + (64 * " 7F"), compileDeltaValues([127] * 64))
		self.assertEqual("3F" + (64 * " 7F") + " 00 7F", compileDeltaValues([127] * 65))
		# words
		self.assertEqual("40 66 66", compileDeltaValues([0x6666]))
		self.assertEqual("43 66 66 7F FF FF FF 80 00", compileDeltaValues([0x6666, 32767, -1, -32768]))
		self.assertEqual("7F" + (64 * " 11 22"), compileDeltaValues([0x1122] * 64))
		self.assertEqual("7F" + (64 * " 11 22") + " 40 11 22", compileDeltaValues([0x1122] * 65))
		# bytes, zeroes, bytes: a single zero is more compact when encoded as part of the bytes run
		self.assertEqual("04 7F 7F 00 7F 7F", compileDeltaValues([127, 127, 0, 127, 127]))
		self.assertEqual("01 7F 7F 81 01 7F 7F", compileDeltaValues([127, 127, 0, 0, 127, 127]))
		self.assertEqual("01 7F 7F 82 01 7F 7F", compileDeltaValues([127, 127, 0, 0, 0, 127, 127]))
		self.assertEqual("01 7F 7F 83 01 7F 7F", compileDeltaValues([127, 127, 0, 0, 0, 0, 127, 127]))
		# bytes, zeroes
		self.assertEqual("01 01 00", compileDeltaValues([1, 0]))
		self.assertEqual("00 01 81", compileDeltaValues([1, 0, 0]))
		# words, bytes, words: a single byte is more compact when encoded as part of the words run
		self.assertEqual("42 66 66 00 02 77 77", compileDeltaValues([0x6666, 2, 0x7777]))
		self.assertEqual("40 66 66 01 02 02 40 77 77", compileDeltaValues([0x6666, 2, 2, 0x7777]))
		# words, zeroes, words
		self.assertEqual("40 66 66 80 40 77 77", compileDeltaValues([0x6666, 0, 0x7777]))
		self.assertEqual("40 66 66 81 40 77 77", compileDeltaValues([0x6666, 0, 0, 0x7777]))
		self.assertEqual("40 66 66 82 40 77 77", compileDeltaValues([0x6666, 0, 0, 0, 0x7777]))
		# words, zeroes, bytes
		self.assertEqual("40 66 66 80 02 01 02 03", compileDeltaValues([0x6666, 0, 1, 2, 3]))
		self.assertEqual("40 66 66 81 02 01 02 03", compileDeltaValues([0x6666, 0, 0, 1, 2, 3]))
		self.assertEqual("40 66 66 82 02 01 02 03", compileDeltaValues([0x6666, 0, 0, 0, 1, 2, 3]))
		# words, zeroes
		self.assertEqual("40 66 66 80", compileDeltaValues([0x6666, 0]))
		self.assertEqual("40 66 66 81", compileDeltaValues([0x6666, 0, 0]))
		# bytes or words from floats
		self.assertEqual("00 01", compileDeltaValues([1.1]))
		self.assertEqual("00 02", compileDeltaValues([1.9]))
		self.assertEqual("40 66 66", compileDeltaValues([0x6666 + 0.1]))
		self.assertEqual("40 66 66", compileDeltaValues([0x6665 + 0.9]))
コード例 #21
0
	def test_compilePoints(self):
		compilePoints = lambda p: TupleVariation.compilePoints(set(p), numPointsInGlyph=999)
		self.assertEqual("00", hexencode(compilePoints(range(999))))  # all points in glyph
		self.assertEqual("01 00 07", hexencode(compilePoints([7])))
		self.assertEqual("01 80 FF FF", hexencode(compilePoints([65535])))
		self.assertEqual("02 01 09 06", hexencode(compilePoints([9, 15])))
		self.assertEqual("06 05 07 01 F7 02 01 F2", hexencode(compilePoints([7, 8, 255, 257, 258, 500])))
		self.assertEqual("03 01 07 01 80 01 EC", hexencode(compilePoints([7, 8, 500])))
		self.assertEqual("04 01 07 01 81 BE E7 0C 0F", hexencode(compilePoints([7, 8, 0xBEEF, 0xCAFE])))
		self.maxDiff = None
		self.assertEqual("81 2C" +  # 300 points (0x12c) in total
				 " 7F 00" + (127 * " 01") +  # first run, contains 128 points: [0 .. 127]
				 " 7F" + (128 * " 01") +  # second run, contains 128 points: [128 .. 255]
				 " 2B" + (44 * " 01"),  # third run, contains 44 points: [256 .. 299]
				 hexencode(compilePoints(range(300))))
		self.assertEqual("81 8F" +  # 399 points (0x18f) in total
				 " 7F 00" + (127 * " 01") +  # first run, contains 128 points: [0 .. 127]
				 " 7F" + (128 * " 01") +  # second run, contains 128 points: [128 .. 255]
				 " 7F" + (128 * " 01") +  # third run, contains 128 points: [256 .. 383]
				 " 0E" + (15 * " 01"),  # fourth run, contains 15 points: [384 .. 398]
				 hexencode(compilePoints(range(399))))
コード例 #22
0
	def test_compileCoord(self):
		var = TupleVariation({"wght": (-1.0, -1.0, -1.0), "wdth": (0.4, 0.5, 0.6)}, [None] * 4)
		self.assertEqual("C0 00 20 00", hexencode(var.compileCoord(["wght", "wdth"])))
		self.assertEqual("20 00 C0 00", hexencode(var.compileCoord(["wdth", "wght"])))
		self.assertEqual("C0 00", hexencode(var.compileCoord(["wght"])))
コード例 #23
0
	def test_compileDeltas_constants(self):
		var = TupleVariation({}, [0, 1, 2, None, 4, 5])
		cvts = {1, 2, 3, 4}
		# delta for cvts: [1, 2, 4]
		self.assertEqual("02 01 02 04", hexencode(var.compileDeltas(cvts)))
コード例 #24
0
	def test_compileDeltas_points(self):
		var = TupleVariation({}, [(0,0), (1, 0), (2, 0), None, (4, 0), (5, 0)])
		points = {1, 2, 3, 4}
		# deltaX for points: [1, 2, 4]; deltaY for points: [0, 0, 0]
		self.assertEqual("02 01 02 04 82", hexencode(var.compileDeltas(points)))
コード例 #25
0
def _add_gvar(font, masterModel, master_ttfs, tolerance=0.5, optimize=True):

    assert tolerance >= 0

    log.info("Generating gvar")
    assert "gvar" not in font
    gvar = font["gvar"] = newTable('gvar')
    gvar.version = 1
    gvar.reserved = 0
    gvar.variations = {}

    for glyph in font.getGlyphOrder():

        allData = [_GetCoordinates(m, glyph) for m in master_ttfs]
        model, allData = masterModel.getSubModel(allData)

        allCoords = [d[0] for d in allData]
        allControls = [d[1] for d in allData]
        control = allControls[0]
        if not models.allEqual(allControls):
            log.warning("glyph %s has incompatible masters; skipping" % glyph)
            continue
        del allControls

        # Update gvar
        gvar.variations[glyph] = []
        deltas = model.getDeltas(allCoords)
        supports = model.supports
        assert len(deltas) == len(supports)

        # Prepare for IUP optimization
        origCoords = deltas[0]
        endPts = control[1] if control[0] >= 1 else list(range(len(
            control[1])))

        for i, (delta, support) in enumerate(zip(deltas[1:], supports[1:])):
            if all(abs(v) <= tolerance for v in delta.array):
                continue
            var = TupleVariation(support, delta)
            if optimize:
                delta_opt = iup_delta_optimize(delta,
                                               origCoords,
                                               endPts,
                                               tolerance=tolerance)

                if None in delta_opt:
                    # Use "optimized" version only if smaller...
                    var_opt = TupleVariation(support, delta_opt)

                    axis_tags = sorted(support.keys(
                    ))  # Shouldn't matter that this is different from fvar...?
                    tupleData, auxData, _ = var.compile(axis_tags, [], None)
                    unoptimized_len = len(tupleData) + len(auxData)
                    tupleData, auxData, _ = var_opt.compile(
                        axis_tags, [], None)
                    optimized_len = len(tupleData) + len(auxData)

                    if optimized_len < unoptimized_len:
                        var = var_opt

            gvar.variations[glyph].append(var)
コード例 #26
0
		def decompilePoints(data, offset):
			points, offset = TupleVariation.decompilePoints_(numPointsInGlyph, deHexStr(data), offset, "gvar")
			# Conversion to list needed for Python 3.
			return (list(points), offset)
コード例 #27
0
def _merge_TTHinting(font, masterModel, master_ttfs, tolerance=0.5):

    log.info("Merging TT hinting")
    assert "cvar" not in font

    # Check that the existing hinting is compatible

    # fpgm and prep table

    for tag in ("fpgm", "prep"):
        all_pgms = [m[tag].program for m in master_ttfs if tag in m]
        if len(all_pgms) == 0:
            continue
        if tag in font:
            font_pgm = font[tag].program
        else:
            font_pgm = Program()
        if any(pgm != font_pgm for pgm in all_pgms):
            log.warning(
                "Masters have incompatible %s tables, hinting is discarded." %
                tag)
            _remove_TTHinting(font)
            return

    # glyf table

    for name, glyph in font["glyf"].glyphs.items():
        all_pgms = [
            m["glyf"][name].program for m in master_ttfs
            if name in m['glyf'] and hasattr(m["glyf"][name], "program")
        ]
        if not any(all_pgms):
            continue
        glyph.expand(font["glyf"])
        if hasattr(glyph, "program"):
            font_pgm = glyph.program
        else:
            font_pgm = Program()
        if any(pgm != font_pgm for pgm in all_pgms if pgm):
            log.warning(
                "Masters have incompatible glyph programs in glyph '%s', hinting is discarded."
                % name)
            # TODO Only drop hinting from this glyph.
            _remove_TTHinting(font)
            return

    # cvt table

    all_cvs = [
        Vector(m["cvt "].values) if 'cvt ' in m else None for m in master_ttfs
    ]

    nonNone_cvs = models.nonNone(all_cvs)
    if not nonNone_cvs:
        # There is no cvt table to make a cvar table from, we're done here.
        return

    if not models.allEqual(len(c) for c in nonNone_cvs):
        log.warning(
            "Masters have incompatible cvt tables, hinting is discarded.")
        _remove_TTHinting(font)
        return

    # We can build the cvar table now.

    cvar = font["cvar"] = newTable('cvar')
    cvar.version = 1
    cvar.variations = []

    deltas, supports = masterModel.getDeltasAndSupports(all_cvs)
    for i, (delta, support) in enumerate(zip(deltas[1:], supports[1:])):
        delta = [otRound(d) for d in delta]
        if all(abs(v) <= tolerance for v in delta):
            continue
        var = TupleVariation(support, delta)
        cvar.variations.append(var)
コード例 #28
0
	def test_hasImpact_allDeltasZero(self):
		axes = {"wght":(0.0, 1.0, 1.0)}
		var = TupleVariation(axes, [(0,0), (0,0), (0,0)])
		self.assertTrue(var.hasImpact())
コード例 #29
0
def _add_gvar(font, masterModel, master_ttfs, tolerance=0.5, optimize=True):

    assert tolerance >= 0

    log.info("Generating gvar")
    assert "gvar" not in font
    gvar = font["gvar"] = newTable('gvar')
    gvar.version = 1
    gvar.reserved = 0
    gvar.variations = {}

    glyf = font['glyf']

    # use hhea.ascent of base master as default vertical origin when vmtx is missing
    defaultVerticalOrigin = font['hhea'].ascent
    for glyph in font.getGlyphOrder():

        isComposite = glyf[glyph].isComposite()

        allData = [
            _GetCoordinates(m,
                            glyph,
                            defaultVerticalOrigin=defaultVerticalOrigin)
            for m in master_ttfs
        ]
        model, allData = masterModel.getSubModel(allData)

        allCoords = [d[0] for d in allData]
        allControls = [d[1] for d in allData]
        control = allControls[0]
        if not models.allEqual(allControls):
            log.warning("glyph %s has incompatible masters; skipping" % glyph)
            continue
        del allControls

        # Update gvar
        gvar.variations[glyph] = []
        deltas = model.getDeltas(allCoords)
        supports = model.supports
        assert len(deltas) == len(supports)

        # Prepare for IUP optimization
        origCoords = deltas[0]
        endPts = control[1] if control[0] >= 1 else list(range(len(
            control[1])))

        for i, (delta, support) in enumerate(zip(deltas[1:], supports[1:])):
            if all(abs(v) <= tolerance
                   for v in delta.array) and not isComposite:
                continue
            var = TupleVariation(support, delta)
            if optimize:
                delta_opt = iup_delta_optimize(delta,
                                               origCoords,
                                               endPts,
                                               tolerance=tolerance)

                if None in delta_opt:
                    """In composite glyphs, there should be one 0 entry
					to make sure the gvar entry is written to the font.

					This is to work around an issue with macOS 10.14 and can be
					removed once the behaviour of macOS is changed.

					https://github.com/fonttools/fonttools/issues/1381
					"""
                    if all(d is None for d in delta_opt):
                        delta_opt = [(0, 0)] + [None] * (len(delta_opt) - 1)
                    # Use "optimized" version only if smaller...
                    var_opt = TupleVariation(support, delta_opt)

                    axis_tags = sorted(support.keys(
                    ))  # Shouldn't matter that this is different from fvar...?
                    tupleData, auxData, _ = var.compile(axis_tags, [], None)
                    unoptimized_len = len(tupleData) + len(auxData)
                    tupleData, auxData, _ = var_opt.compile(
                        axis_tags, [], None)
                    optimized_len = len(tupleData) + len(auxData)

                    if optimized_len < unoptimized_len:
                        var = var_opt

            gvar.variations[glyph].append(var)
コード例 #30
0
ファイル: __init__.py プロジェクト: khaledhosny/fonttools
def _add_gvar(font, masterModel, master_ttfs, tolerance=0.5, optimize=True):

	assert tolerance >= 0

	log.info("Generating gvar")
	assert "gvar" not in font
	gvar = font["gvar"] = newTable('gvar')
	gvar.version = 1
	gvar.reserved = 0
	gvar.variations = {}

	glyf = font['glyf']

	for glyph in font.getGlyphOrder():

		isComposite = glyf[glyph].isComposite()

		allData = [_GetCoordinates(m, glyph) for m in master_ttfs]
		model, allData = masterModel.getSubModel(allData)

		allCoords = [d[0] for d in allData]
		allControls = [d[1] for d in allData]
		control = allControls[0]
		if not models.allEqual(allControls):
			log.warning("glyph %s has incompatible masters; skipping" % glyph)
			continue
		del allControls

		# Update gvar
		gvar.variations[glyph] = []
		deltas = model.getDeltas(allCoords)
		supports = model.supports
		assert len(deltas) == len(supports)

		# Prepare for IUP optimization
		origCoords = deltas[0]
		endPts = control[1] if control[0] >= 1 else list(range(len(control[1])))

		for i,(delta,support) in enumerate(zip(deltas[1:], supports[1:])):
			if all(abs(v) <= tolerance for v in delta.array) and not isComposite:
				continue
			var = TupleVariation(support, delta)
			if optimize:
				delta_opt = iup_delta_optimize(delta, origCoords, endPts, tolerance=tolerance)

				if None in delta_opt:
					"""In composite glyphs, there should be one 0 entry
					to make sure the gvar entry is written to the font.

					This is to work around an issue with macOS 10.14 and can be
					removed once the behaviour of macOS is changed.

					https://github.com/fonttools/fonttools/issues/1381
					"""
					if all(d is None for d in delta_opt):
						delta_opt = [(0, 0)] + [None] * (len(delta_opt) - 1)
					# Use "optimized" version only if smaller...
					var_opt = TupleVariation(support, delta_opt)

					axis_tags = sorted(support.keys()) # Shouldn't matter that this is different from fvar...?
					tupleData, auxData, _ = var.compile(axis_tags, [], None)
					unoptimized_len = len(tupleData) + len(auxData)
					tupleData, auxData, _ = var_opt.compile(axis_tags, [], None)
					optimized_len = len(tupleData) + len(auxData)

					if optimized_len < unoptimized_len:
						var = var_opt

			gvar.variations[glyph].append(var)
コード例 #31
0
	def test_hasImpact_someDeltasNotZero(self):
		axes = {"wght":(0.0, 1.0, 1.0)}
		var = TupleVariation(axes, [(0,0), (9,8), (7,6)])
		self.assertTrue(var.hasImpact())
コード例 #32
0
	def test_compileIntermediateCoord(self):
		var = TupleVariation({"wght": (-1.0, -1.0, 0.0), "wdth": (0.4, 0.5, 0.6)}, [None] * 4)
		self.assertEqual("C0 00 19 9A 00 00 26 66", hexencode(var.compileIntermediateCoord(["wght", "wdth"])))
		self.assertEqual("19 9A C0 00 26 66 00 00", hexencode(var.compileIntermediateCoord(["wdth", "wght"])))
		self.assertEqual(None, var.compileIntermediateCoord(["wght"]))
		self.assertEqual("19 9A 26 66", hexencode(var.compileIntermediateCoord(["wdth"])))
コード例 #33
0
	def test_hasImpact_allDeltasNone(self):
		axes = {"wght":(0.0, 1.0, 1.0)}
		var = TupleVariation(axes, [None, None, None])
		self.assertFalse(var.hasImpact())
コード例 #34
0
def test_build_var(tmpdir):
    outPath = os.path.join(str(tmpdir), "test_var.ttf")

    fb, advanceWidths, nameStrings = _setupFontBuilder(True)

    pen = TTGlyphPen(None)
    pen.moveTo((100, 0))
    pen.lineTo((100, 400))
    pen.lineTo((500, 400))
    pen.lineTo((500, 000))
    pen.closePath()

    glyph = pen.glyph()

    pen = TTGlyphPen(None)
    emptyGlyph = pen.glyph()

    glyphs = {
        ".notdef": emptyGlyph,
        "A": glyph,
        "a": glyph,
        ".null": emptyGlyph
    }
    fb.setupGlyf(glyphs)
    metrics = {}
    glyphTable = fb.font["glyf"]
    for gn, advanceWidth in advanceWidths.items():
        metrics[gn] = (advanceWidth, glyphTable[gn].xMin)
    fb.setupHorizontalMetrics(metrics)

    fb.setupHorizontalHeader(ascent=824, descent=200)
    fb.setupNameTable(nameStrings)

    axes = [
        ('LEFT', 0, 0, 100, "Left"),
        ('RGHT', 0, 0, 100, "Right"),
        ('UPPP', 0, 0, 100, "Up"),
        ('DOWN', 0, 0, 100, "Down"),
    ]
    instances = [
        dict(location=dict(LEFT=0, RGHT=0, UPPP=0, DOWN=0),
             stylename="TotallyNormal"),
        dict(location=dict(LEFT=0, RGHT=100, UPPP=100, DOWN=0),
             stylename="Right Up"),
    ]
    fb.setupFvar(axes, instances)
    variations = {}
    # Four (x, y) pairs and four phantom points:
    leftDeltas = [(-200, 0), (-200, 0), (0, 0), (0, 0), None, None, None, None]
    rightDeltas = [(0, 0), (0, 0), (200, 0), (200, 0), None, None, None, None]
    upDeltas = [(0, 0), (0, 200), (0, 200), (0, 0), None, None, None, None]
    downDeltas = [(0, -200), (0, 0), (0, 0), (0, -200), None, None, None, None]
    variations['a'] = [
        TupleVariation(dict(RGHT=(0, 1, 1)), rightDeltas),
        TupleVariation(dict(LEFT=(0, 1, 1)), leftDeltas),
        TupleVariation(dict(UPPP=(0, 1, 1)), upDeltas),
        TupleVariation(dict(DOWN=(0, 1, 1)), downDeltas),
    ]
    fb.setupGvar(variations)

    fb.setupOS2()
    fb.setupPost()
    fb.setupDummyDSIG()

    fb.save(outPath)

    _verifyOutput(outPath)