blob: 4a8e76718af96fa83443067b1c1a62a0567561bf [file] [log] [blame]
from __future__ import print_function, division, absolute_import, unicode_literals
from fontTools.misc.py23 import *
from fontTools.misc.testTools import parseXML
from fontTools.misc.textTools import deHexStr
from fontTools.misc.xmlWriter import XMLWriter
from fontTools.ttLib import TTLibError
from fontTools.ttLib.tables._f_v_a_r import table__f_v_a_r, Axis, NamedInstance
from fontTools.ttLib.tables._n_a_m_e import table__n_a_m_e, NameRecord
import unittest
FVAR_DATA = deHexStr(
"00 01 00 00 00 10 00 02 00 02 00 14 00 02 00 0C "
"77 67 68 74 00 64 00 00 01 90 00 00 03 84 00 00 00 00 01 01 "
"77 64 74 68 00 32 00 00 00 64 00 00 00 c8 00 00 00 00 01 02 "
"01 03 00 00 01 2c 00 00 00 64 00 00 "
"01 04 00 00 01 2c 00 00 00 4b 00 00")
FVAR_AXIS_DATA = deHexStr(
"6F 70 73 7a ff ff 80 00 00 01 4c cd 00 01 80 00 00 00 01 59")
FVAR_INSTANCE_DATA_WITHOUT_PSNAME = deHexStr(
"01 59 00 00 00 00 b3 33 00 00 80 00")
FVAR_INSTANCE_DATA_WITH_PSNAME = (
FVAR_INSTANCE_DATA_WITHOUT_PSNAME + deHexStr("02 34"))
def xml_lines(writer):
content = writer.file.getvalue().decode("utf-8")
return [line.strip() for line in content.splitlines()][1:]
def AddName(font, name):
nameTable = font.get("name")
if nameTable is None:
nameTable = font["name"] = table__n_a_m_e()
nameTable.names = []
namerec = NameRecord()
namerec.nameID = 1 + max([n.nameID for n in nameTable.names] + [256])
namerec.string = name.encode('mac_roman')
namerec.platformID, namerec.platEncID, namerec.langID = (1, 0, 0)
nameTable.names.append(namerec)
return namerec
def MakeFont():
axes = [("wght", "Weight", 100, 400, 900), ("wdth", "Width", 50, 100, 200)]
instances = [("Light", 300, 100), ("Light Condensed", 300, 75)]
fvarTable = table__f_v_a_r()
font = {"fvar": fvarTable}
for tag, name, minValue, defaultValue, maxValue in axes:
axis = Axis()
axis.axisTag = tag
axis.defaultValue = defaultValue
axis.minValue, axis.maxValue = minValue, maxValue
axis.axisNameID = AddName(font, name).nameID
fvarTable.axes.append(axis)
for name, weight, width in instances:
inst = NamedInstance()
inst.subfamilyNameID = AddName(font, name).nameID
inst.coordinates = {"wght": weight, "wdth": width}
fvarTable.instances.append(inst)
return font
class FontVariationTableTest(unittest.TestCase):
def test_compile(self):
font = MakeFont()
h = font["fvar"].compile(font)
self.assertEqual(FVAR_DATA, font["fvar"].compile(font))
def test_decompile(self):
fvar = table__f_v_a_r()
fvar.decompile(FVAR_DATA, ttFont={"fvar": fvar})
self.assertEqual(["wght", "wdth"], [a.axisTag for a in fvar.axes])
self.assertEqual([259, 260], [i.subfamilyNameID for i in fvar.instances])
def test_toXML(self):
font = MakeFont()
writer = XMLWriter(BytesIO())
font["fvar"].toXML(writer, font)
xml = writer.file.getvalue().decode("utf-8")
self.assertEqual(2, xml.count("<Axis>"))
self.assertTrue("<AxisTag>wght</AxisTag>" in xml)
self.assertTrue("<AxisTag>wdth</AxisTag>" in xml)
self.assertEqual(2, xml.count("<NamedInstance "))
self.assertTrue("<!-- Light -->" in xml)
self.assertTrue("<!-- Light Condensed -->" in xml)
def test_fromXML(self):
fvar = table__f_v_a_r()
for name, attrs, content in parseXML(
'<Axis>'
' <AxisTag>opsz</AxisTag>'
'</Axis>'
'<Axis>'
' <AxisTag>slnt</AxisTag>'
' <Flags>0x123</Flags>'
'</Axis>'
'<NamedInstance subfamilyNameID="765"/>'
'<NamedInstance subfamilyNameID="234"/>'):
fvar.fromXML(name, attrs, content, ttFont=None)
self.assertEqual(["opsz", "slnt"], [a.axisTag for a in fvar.axes])
self.assertEqual([0, 0x123], [a.flags for a in fvar.axes])
self.assertEqual([765, 234], [i.subfamilyNameID for i in fvar.instances])
class AxisTest(unittest.TestCase):
def test_compile(self):
axis = Axis()
axis.axisTag, axis.axisNameID = ('opsz', 345)
axis.minValue, axis.defaultValue, axis.maxValue = (-0.5, 1.3, 1.5)
self.assertEqual(FVAR_AXIS_DATA, axis.compile())
def test_decompile(self):
axis = Axis()
axis.decompile(FVAR_AXIS_DATA)
self.assertEqual("opsz", axis.axisTag)
self.assertEqual(345, axis.axisNameID)
self.assertEqual(-0.5, axis.minValue)
self.assertEqual(1.3, axis.defaultValue)
self.assertEqual(1.5, axis.maxValue)
def test_toXML(self):
font = MakeFont()
axis = Axis()
axis.decompile(FVAR_AXIS_DATA)
AddName(font, "Optical Size").nameID = 256
axis.axisNameID = 256
axis.flags = 0xABC
writer = XMLWriter(BytesIO())
axis.toXML(writer, font)
self.assertEqual([
'',
'<!-- Optical Size -->',
'<Axis>',
'<AxisTag>opsz</AxisTag>',
'<Flags>0xABC</Flags>',
'<MinValue>-0.5</MinValue>',
'<DefaultValue>1.3</DefaultValue>',
'<MaxValue>1.5</MaxValue>',
'<AxisNameID>256</AxisNameID>',
'</Axis>'
], xml_lines(writer))
def test_fromXML(self):
axis = Axis()
for name, attrs, content in parseXML(
'<Axis>'
' <AxisTag>wght</AxisTag>'
' <Flags>0x123ABC</Flags>'
' <MinValue>100</MinValue>'
' <DefaultValue>400</DefaultValue>'
' <MaxValue>900</MaxValue>'
' <AxisNameID>256</AxisNameID>'
'</Axis>'):
axis.fromXML(name, attrs, content, ttFont=None)
self.assertEqual("wght", axis.axisTag)
self.assertEqual(0x123ABC, axis.flags)
self.assertEqual(100, axis.minValue)
self.assertEqual(400, axis.defaultValue)
self.assertEqual(900, axis.maxValue)
self.assertEqual(256, axis.axisNameID)
class NamedInstanceTest(unittest.TestCase):
def test_compile_withPostScriptName(self):
inst = NamedInstance()
inst.subfamilyNameID = 345
inst.postscriptNameID = 564
inst.coordinates = {"wght": 0.7, "wdth": 0.5}
self.assertEqual(FVAR_INSTANCE_DATA_WITH_PSNAME,
inst.compile(["wght", "wdth"], True))
def test_compile_withoutPostScriptName(self):
inst = NamedInstance()
inst.subfamilyNameID = 345
inst.postscriptNameID = 564
inst.coordinates = {"wght": 0.7, "wdth": 0.5}
self.assertEqual(FVAR_INSTANCE_DATA_WITHOUT_PSNAME,
inst.compile(["wght", "wdth"], False))
def test_decompile_withPostScriptName(self):
inst = NamedInstance()
inst.decompile(FVAR_INSTANCE_DATA_WITH_PSNAME, ["wght", "wdth"])
self.assertEqual(564, inst.postscriptNameID)
self.assertEqual(345, inst.subfamilyNameID)
self.assertEqual({"wght": 0.7, "wdth": 0.5}, inst.coordinates)
def test_decompile_withoutPostScriptName(self):
inst = NamedInstance()
inst.decompile(FVAR_INSTANCE_DATA_WITHOUT_PSNAME, ["wght", "wdth"])
self.assertEqual(0xFFFF, inst.postscriptNameID)
self.assertEqual(345, inst.subfamilyNameID)
self.assertEqual({"wght": 0.7, "wdth": 0.5}, inst.coordinates)
def test_toXML_withPostScriptName(self):
font = MakeFont()
inst = NamedInstance()
inst.flags = 0xE9
inst.subfamilyNameID = AddName(font, "Light Condensed").nameID
inst.postscriptNameID = AddName(font, "Test-LightCondensed").nameID
inst.coordinates = {"wght": 0.7, "wdth": 0.5}
writer = XMLWriter(BytesIO())
inst.toXML(writer, font)
self.assertEqual([
'',
'<!-- Light Condensed -->',
'<!-- PostScript: Test-LightCondensed -->',
'<NamedInstance flags="0xE9" postscriptNameID="%s" subfamilyNameID="%s">' % (
inst.postscriptNameID, inst.subfamilyNameID),
'<coord axis="wght" value="0.7"/>',
'<coord axis="wdth" value="0.5"/>',
'</NamedInstance>'
], xml_lines(writer))
def test_toXML_withoutPostScriptName(self):
font = MakeFont()
inst = NamedInstance()
inst.flags = 0xABC
inst.subfamilyNameID = AddName(font, "Light Condensed").nameID
inst.coordinates = {"wght": 0.7, "wdth": 0.5}
writer = XMLWriter(BytesIO())
inst.toXML(writer, font)
self.assertEqual([
'',
'<!-- Light Condensed -->',
'<NamedInstance flags="0xABC" subfamilyNameID="%s">' %
inst.subfamilyNameID,
'<coord axis="wght" value="0.7"/>',
'<coord axis="wdth" value="0.5"/>',
'</NamedInstance>'
], xml_lines(writer))
def test_fromXML_withPostScriptName(self):
inst = NamedInstance()
for name, attrs, content in parseXML(
'<NamedInstance flags="0x0" postscriptNameID="257" subfamilyNameID="345">'
' <coord axis="wght" value="0.7"/>'
' <coord axis="wdth" value="0.5"/>'
'</NamedInstance>'):
inst.fromXML(name, attrs, content, ttFont=MakeFont())
self.assertEqual(257, inst.postscriptNameID)
self.assertEqual(345, inst.subfamilyNameID)
self.assertEqual({"wght": 0.7, "wdth": 0.5}, inst.coordinates)
def test_fromXML_withoutPostScriptName(self):
inst = NamedInstance()
for name, attrs, content in parseXML(
'<NamedInstance flags="0x123ABC" subfamilyNameID="345">'
' <coord axis="wght" value="0.7"/>'
' <coord axis="wdth" value="0.5"/>'
'</NamedInstance>'):
inst.fromXML(name, attrs, content, ttFont=MakeFont())
self.assertEqual(0x123ABC, inst.flags)
self.assertEqual(345, inst.subfamilyNameID)
self.assertEqual({"wght": 0.7, "wdth": 0.5}, inst.coordinates)
if __name__ == "__main__":
import sys
sys.exit(unittest.main())