Merge pull request #300 from brawer/fvar
[GX] Make it easier to construct ‘fvar’ tables from code
This commit is contained in:
commit
389c445760
@ -29,8 +29,7 @@ class table__a_v_a_r(DefaultTable.DefaultTable):
|
|||||||
self.segments = {}
|
self.segments = {}
|
||||||
|
|
||||||
def compile(self, ttFont):
|
def compile(self, ttFont):
|
||||||
fvarAxes = ttFont["fvar"].table.VariationAxis
|
axisTags = [axis.axisTag for axis in ttFont["fvar"].axes]
|
||||||
axisTags = [axis.AxisTag for axis in fvarAxes]
|
|
||||||
header = {"version": 0x00010000, "axisCount": len(axisTags)}
|
header = {"version": 0x00010000, "axisCount": len(axisTags)}
|
||||||
result = [sstruct.pack(AVAR_HEADER_FORMAT, header)]
|
result = [sstruct.pack(AVAR_HEADER_FORMAT, header)]
|
||||||
for axis in axisTags:
|
for axis in axisTags:
|
||||||
@ -43,8 +42,7 @@ class table__a_v_a_r(DefaultTable.DefaultTable):
|
|||||||
return bytesjoin(result)
|
return bytesjoin(result)
|
||||||
|
|
||||||
def decompile(self, data, ttFont):
|
def decompile(self, data, ttFont):
|
||||||
fvarAxes = ttFont["fvar"].table.VariationAxis
|
axisTags = [axis.axisTag for axis in ttFont["fvar"].axes]
|
||||||
axisTags = [axis.AxisTag for axis in fvarAxes]
|
|
||||||
header = {}
|
header = {}
|
||||||
headerSize = sstruct.calcsize(AVAR_HEADER_FORMAT)
|
headerSize = sstruct.calcsize(AVAR_HEADER_FORMAT)
|
||||||
header = sstruct.unpack(AVAR_HEADER_FORMAT, data[0:headerSize])
|
header = sstruct.unpack(AVAR_HEADER_FORMAT, data[0:headerSize])
|
||||||
@ -62,7 +60,7 @@ class table__a_v_a_r(DefaultTable.DefaultTable):
|
|||||||
self.fixupSegments_(warn=warnings.warn)
|
self.fixupSegments_(warn=warnings.warn)
|
||||||
|
|
||||||
def toXML(self, writer, ttFont, progress=None):
|
def toXML(self, writer, ttFont, progress=None):
|
||||||
axisTags = [axis.AxisTag for axis in ttFont["fvar"].table.VariationAxis]
|
axisTags = [axis.axisTag for axis in ttFont["fvar"].axes]
|
||||||
for axis in axisTags:
|
for axis in axisTags:
|
||||||
writer.begintag("segment", axis=axis)
|
writer.begintag("segment", axis=axis)
|
||||||
writer.newline()
|
writer.newline()
|
||||||
|
@ -4,6 +4,7 @@ from fontTools.misc.textTools import deHexStr
|
|||||||
from fontTools.misc.xmlWriter import XMLWriter
|
from fontTools.misc.xmlWriter import XMLWriter
|
||||||
from fontTools.ttLib import TTLibError
|
from fontTools.ttLib import TTLibError
|
||||||
from fontTools.ttLib.tables._a_v_a_r import table__a_v_a_r
|
from fontTools.ttLib.tables._a_v_a_r import table__a_v_a_r
|
||||||
|
from fontTools.ttLib.tables._f_v_a_r import table__f_v_a_r, Axis
|
||||||
import collections
|
import collections
|
||||||
import unittest
|
import unittest
|
||||||
|
|
||||||
@ -73,9 +74,11 @@ class AxisVariationTableTest(unittest.TestCase):
|
|||||||
@staticmethod
|
@staticmethod
|
||||||
def makeFont(axisTags):
|
def makeFont(axisTags):
|
||||||
"""['opsz', 'wdth'] --> ttFont"""
|
"""['opsz', 'wdth'] --> ttFont"""
|
||||||
axes = [collections.namedtuple("A", "AxisTag")(axis) for axis in axisTags]
|
fvar = table__f_v_a_r()
|
||||||
varaxis = collections.namedtuple("B", "VariationAxis")(axes)
|
for tag in axisTags:
|
||||||
fvar = collections.namedtuple("C", "table")(varaxis)
|
axis = Axis()
|
||||||
|
axis.axisTag = tag
|
||||||
|
fvar.axes.append(axis)
|
||||||
return {"fvar": fvar}
|
return {"fvar": fvar}
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
@ -1,7 +1,192 @@
|
|||||||
from __future__ import print_function, division, absolute_import
|
from __future__ import print_function, division, absolute_import
|
||||||
from fontTools.misc.py23 import *
|
from fontTools.misc.py23 import *
|
||||||
from .otBase import BaseTTXConverter
|
from fontTools.misc import sstruct
|
||||||
|
from fontTools.misc.fixedTools import fixedToFloat, floatToFixed
|
||||||
|
from fontTools.misc.textTools import safeEval, num2binary, binary2num
|
||||||
|
from fontTools.ttLib import TTLibError
|
||||||
|
from . import DefaultTable
|
||||||
|
import struct
|
||||||
|
|
||||||
|
|
||||||
class table__f_v_a_r(BaseTTXConverter):
|
# Apple's documentation of 'fvar':
|
||||||
pass
|
# https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6fvar.html
|
||||||
|
|
||||||
|
FVAR_HEADER_FORMAT = """
|
||||||
|
> # big endian
|
||||||
|
version: L
|
||||||
|
offsetToData: H
|
||||||
|
countSizePairs: H
|
||||||
|
axisCount: H
|
||||||
|
axisSize: H
|
||||||
|
instanceCount: H
|
||||||
|
instanceSize: H
|
||||||
|
"""
|
||||||
|
|
||||||
|
FVAR_AXIS_FORMAT = """
|
||||||
|
> # big endian
|
||||||
|
axisTag: 4s
|
||||||
|
minValue: 16.16F
|
||||||
|
defaultValue: 16.16F
|
||||||
|
maxValue: 16.16F
|
||||||
|
flags: H
|
||||||
|
nameID: H
|
||||||
|
"""
|
||||||
|
|
||||||
|
FVAR_INSTANCE_FORMAT = """
|
||||||
|
> # big endian
|
||||||
|
nameID: H
|
||||||
|
flags: H
|
||||||
|
"""
|
||||||
|
|
||||||
|
class table__f_v_a_r(DefaultTable.DefaultTable):
|
||||||
|
dependencies = ["name"]
|
||||||
|
|
||||||
|
def __init__(self, tag="fvar"):
|
||||||
|
DefaultTable.DefaultTable.__init__(self, tag)
|
||||||
|
self.axes = []
|
||||||
|
self.instances = []
|
||||||
|
|
||||||
|
def compile(self, ttFont):
|
||||||
|
header = {
|
||||||
|
"version": 0x00010000,
|
||||||
|
"offsetToData": sstruct.calcsize(FVAR_HEADER_FORMAT),
|
||||||
|
"countSizePairs": 2,
|
||||||
|
"axisCount": len(self.axes),
|
||||||
|
"axisSize": sstruct.calcsize(FVAR_AXIS_FORMAT),
|
||||||
|
"instanceCount": len(self.instances),
|
||||||
|
"instanceSize": sstruct.calcsize(FVAR_INSTANCE_FORMAT) + len(self.axes) * 4
|
||||||
|
}
|
||||||
|
result = [sstruct.pack(FVAR_HEADER_FORMAT, header)]
|
||||||
|
result.extend([axis.compile() for axis in self.axes])
|
||||||
|
axisTags = [axis.axisTag for axis in self.axes]
|
||||||
|
result.extend([instance.compile(axisTags) for instance in self.instances])
|
||||||
|
return bytesjoin(result)
|
||||||
|
|
||||||
|
def decompile(self, data, ttFont):
|
||||||
|
header = {}
|
||||||
|
headerSize = sstruct.calcsize(FVAR_HEADER_FORMAT)
|
||||||
|
header = sstruct.unpack(FVAR_HEADER_FORMAT, data[0:headerSize])
|
||||||
|
if header["version"] != 0x00010000:
|
||||||
|
raise TTLibError("unsupported 'fvar' version %04x" % header["version"])
|
||||||
|
pos = header["offsetToData"]
|
||||||
|
axisSize = header["axisSize"]
|
||||||
|
for _ in range(header["axisCount"]):
|
||||||
|
axis = Axis()
|
||||||
|
axis.decompile(data[pos:pos+axisSize])
|
||||||
|
self.axes.append(axis)
|
||||||
|
pos += axisSize
|
||||||
|
instanceSize = header["instanceSize"]
|
||||||
|
axisTags = [axis.axisTag for axis in self.axes]
|
||||||
|
for _ in range(header["instanceCount"]):
|
||||||
|
instance = NamedInstance()
|
||||||
|
instance.decompile(data[pos:pos+instanceSize], axisTags)
|
||||||
|
self.instances.append(instance)
|
||||||
|
pos += instanceSize
|
||||||
|
|
||||||
|
def toXML(self, writer, ttFont, progress=None):
|
||||||
|
for axis in self.axes:
|
||||||
|
axis.toXML(writer, ttFont)
|
||||||
|
for instance in self.instances:
|
||||||
|
instance.toXML(writer, ttFont)
|
||||||
|
|
||||||
|
def fromXML(self, name, attrs, content, ttFont):
|
||||||
|
if name == "Axis":
|
||||||
|
axis = Axis()
|
||||||
|
axis.fromXML(name, attrs, content, ttFont)
|
||||||
|
self.axes.append(axis)
|
||||||
|
elif name == "NamedInstance":
|
||||||
|
instance = NamedInstance()
|
||||||
|
instance.fromXML(name, attrs, content, ttFont)
|
||||||
|
self.instances.append(instance)
|
||||||
|
|
||||||
|
class Axis(object):
|
||||||
|
def __init__(self):
|
||||||
|
self.axisTag = None
|
||||||
|
self.nameID = 0
|
||||||
|
self.flags = 0
|
||||||
|
self.minValue = -1.0
|
||||||
|
self.defaultValue = 0.0
|
||||||
|
self.maxValue = 1.0
|
||||||
|
|
||||||
|
def compile(self):
|
||||||
|
return sstruct.pack(FVAR_AXIS_FORMAT, self)
|
||||||
|
|
||||||
|
def decompile(self, data):
|
||||||
|
sstruct.unpack2(FVAR_AXIS_FORMAT, data, self)
|
||||||
|
|
||||||
|
def toXML(self, writer, ttFont):
|
||||||
|
name = ttFont["name"].getDebugName(self.nameID)
|
||||||
|
if name is not None:
|
||||||
|
writer.newline()
|
||||||
|
writer.comment(name)
|
||||||
|
writer.newline()
|
||||||
|
writer.begintag("Axis")
|
||||||
|
writer.newline()
|
||||||
|
for tag, value in [("AxisTag", self.axisTag),
|
||||||
|
("MinValue", str(self.minValue)),
|
||||||
|
("DefaultValue", str(self.defaultValue)),
|
||||||
|
("MaxValue", str(self.maxValue)),
|
||||||
|
("Flags", num2binary(self.flags, 16)),
|
||||||
|
("NameID", str(self.nameID))]:
|
||||||
|
writer.begintag(tag)
|
||||||
|
writer.write(value)
|
||||||
|
writer.endtag(tag)
|
||||||
|
writer.newline()
|
||||||
|
writer.endtag("Axis")
|
||||||
|
writer.newline()
|
||||||
|
|
||||||
|
def fromXML(self, name, _attrs, content, ttFont):
|
||||||
|
assert(name == "Axis")
|
||||||
|
for tag, _, value in filter(lambda t: type(t) is tuple, content):
|
||||||
|
value = ''.join(value)
|
||||||
|
if tag == "AxisTag":
|
||||||
|
self.axisTag = value
|
||||||
|
elif tag == "Flags":
|
||||||
|
self.flags = binary2num(value)
|
||||||
|
elif tag in ["MinValue", "DefaultValue", "MaxValue", "NameID"]:
|
||||||
|
setattr(self, tag[0].lower() + tag[1:], safeEval(value))
|
||||||
|
|
||||||
|
class NamedInstance(object):
|
||||||
|
def __init__(self):
|
||||||
|
self.nameID = 0
|
||||||
|
self.flags = 0
|
||||||
|
self.coordinates = {}
|
||||||
|
|
||||||
|
def compile(self, axisTags):
|
||||||
|
result = [sstruct.pack(FVAR_INSTANCE_FORMAT, self)]
|
||||||
|
for axis in axisTags:
|
||||||
|
fixedCoord = floatToFixed(self.coordinates[axis], 16)
|
||||||
|
result.append(struct.pack(">l", fixedCoord))
|
||||||
|
return bytesjoin(result)
|
||||||
|
|
||||||
|
def decompile(self, data, axisTags):
|
||||||
|
sstruct.unpack2(FVAR_INSTANCE_FORMAT, data, self)
|
||||||
|
pos = sstruct.calcsize(FVAR_INSTANCE_FORMAT)
|
||||||
|
for axis in axisTags:
|
||||||
|
value = struct.unpack(">l", data[pos : pos + 4])[0]
|
||||||
|
self.coordinates[axis] = fixedToFloat(value, 16)
|
||||||
|
pos += 4
|
||||||
|
|
||||||
|
def toXML(self, writer, ttFont):
|
||||||
|
name = ttFont["name"].getDebugName(self.nameID)
|
||||||
|
if name is not None:
|
||||||
|
writer.newline()
|
||||||
|
writer.comment(name)
|
||||||
|
writer.newline()
|
||||||
|
writer.begintag("NamedInstance", nameID=self.nameID,
|
||||||
|
flags=num2binary(self.flags, 16))
|
||||||
|
writer.newline()
|
||||||
|
for axis in ttFont["fvar"].axes:
|
||||||
|
writer.simpletag("coord", axis=axis.axisTag,
|
||||||
|
value=self.coordinates[axis.axisTag])
|
||||||
|
writer.newline()
|
||||||
|
writer.endtag("NamedInstance")
|
||||||
|
writer.newline()
|
||||||
|
|
||||||
|
def fromXML(self, name, attrs, content, ttFont):
|
||||||
|
assert(name == "NamedInstance")
|
||||||
|
self.flags = binary2num(attrs.get("flags", "0"))
|
||||||
|
self.nameID = safeEval(attrs["nameID"])
|
||||||
|
for tag, elementAttrs, _ in filter(lambda t: type(t) is tuple, content):
|
||||||
|
if tag == "coord":
|
||||||
|
self.coordinates[elementAttrs["axis"]] = safeEval(elementAttrs["value"])
|
||||||
|
195
Lib/fontTools/ttLib/tables/_f_v_a_r_test.py
Normal file
195
Lib/fontTools/ttLib/tables/_f_v_a_r_test.py
Normal file
@ -0,0 +1,195 @@
|
|||||||
|
from __future__ import print_function, division, absolute_import, unicode_literals
|
||||||
|
from fontTools.misc.py23 import *
|
||||||
|
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 FF FF 00 00 00 00 00 00 00 01 00 00 00 00 01 01 "
|
||||||
|
"77 64 74 68 FF FF 00 00 00 00 00 00 00 01 00 00 00 00 01 02 "
|
||||||
|
"01 03 00 00 00 00 4C CD 00 01 00 00 "
|
||||||
|
"01 04 00 00 00 00 4C CD 00 00 33 33")
|
||||||
|
|
||||||
|
FVAR_AXIS_DATA = deHexStr(
|
||||||
|
"6F 70 73 7a ff ff 80 00 00 01 4c cd 00 01 80 00 98 76 01 59")
|
||||||
|
|
||||||
|
FVAR_INSTANCE_DATA = deHexStr("01 59 12 34 00 00 b3 33 00 00 80 00")
|
||||||
|
|
||||||
|
|
||||||
|
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"), ("wdth", "Width")]
|
||||||
|
instances = [("Light", 0.3, 1.0), ("Light Condensed", 0.3, 0.2)]
|
||||||
|
fvarTable = table__f_v_a_r()
|
||||||
|
font = {"fvar": fvarTable}
|
||||||
|
for tag, name in axes:
|
||||||
|
axis = Axis()
|
||||||
|
axis.axisTag = tag
|
||||||
|
axis.nameID = AddName(font, name).nameID
|
||||||
|
fvarTable.axes.append(axis)
|
||||||
|
for name, weight, width in instances:
|
||||||
|
inst = NamedInstance()
|
||||||
|
inst.nameID = 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.nameID for i in fvar.instances])
|
||||||
|
|
||||||
|
def test_toXML(self):
|
||||||
|
font = MakeFont()
|
||||||
|
writer = XMLWriter(StringIO())
|
||||||
|
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()
|
||||||
|
fvar.fromXML("Axis", {}, [("AxisTag", {}, ["opsz"])], ttFont=None)
|
||||||
|
fvar.fromXML("Axis", {}, [("AxisTag", {}, ["slnt"])], ttFont=None)
|
||||||
|
fvar.fromXML("NamedInstance", {"nameID": "765"}, [], ttFont=None)
|
||||||
|
fvar.fromXML("NamedInstance", {"nameID": "234"}, [], ttFont=None)
|
||||||
|
self.assertEqual(["opsz", "slnt"], [a.axisTag for a in fvar.axes])
|
||||||
|
self.assertEqual([765, 234], [i.nameID for i in fvar.instances])
|
||||||
|
|
||||||
|
|
||||||
|
class AxisTest(unittest.TestCase):
|
||||||
|
def test_compile(self):
|
||||||
|
axis = Axis()
|
||||||
|
axis.axisTag, axis.nameID, axis.flags = ('opsz', 345, 0x9876)
|
||||||
|
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.nameID)
|
||||||
|
self.assertEqual(0x9876, axis.flags)
|
||||||
|
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.nameID = 256
|
||||||
|
writer = XMLWriter(StringIO())
|
||||||
|
axis.toXML(writer, font)
|
||||||
|
self.assertEqual([
|
||||||
|
'',
|
||||||
|
'<!-- Optical Size -->',
|
||||||
|
'<Axis>',
|
||||||
|
'<AxisTag>opsz</AxisTag>',
|
||||||
|
'<MinValue>-0.5</MinValue>',
|
||||||
|
'<DefaultValue>1.3</DefaultValue>',
|
||||||
|
'<MaxValue>1.5</MaxValue>',
|
||||||
|
'<Flags>10011000 01110110</Flags>',
|
||||||
|
'<NameID>256</NameID>',
|
||||||
|
'</Axis>'
|
||||||
|
], xml_lines(writer))
|
||||||
|
|
||||||
|
def test_fromXML(self):
|
||||||
|
axis = Axis()
|
||||||
|
axis.fromXML("Axis", {}, [
|
||||||
|
("AxisTag", {}, ["opsz"]),
|
||||||
|
("MinValue", {}, ["-0.5"]),
|
||||||
|
("DefaultValue", {}, ["1.3"]),
|
||||||
|
("MaxValue", {}, ["1.5"]),
|
||||||
|
("Flags", {}, ["10011000 01110110"]),
|
||||||
|
("NameID", {}, ["256"])
|
||||||
|
], ttFont=None)
|
||||||
|
self.assertEqual("opsz", axis.axisTag)
|
||||||
|
self.assertEqual(-0.5, axis.minValue)
|
||||||
|
self.assertEqual(1.3, axis.defaultValue)
|
||||||
|
self.assertEqual(1.5, axis.maxValue)
|
||||||
|
self.assertEqual(0x9876, axis.flags)
|
||||||
|
self.assertEqual(256, axis.nameID)
|
||||||
|
|
||||||
|
|
||||||
|
class NamedInstanceTest(unittest.TestCase):
|
||||||
|
def test_compile(self):
|
||||||
|
inst = NamedInstance()
|
||||||
|
inst.nameID = 345
|
||||||
|
inst.flags = 0x1234
|
||||||
|
inst.coordinates = {"wght": 0.7, "wdth": 0.5}
|
||||||
|
self.assertEqual(FVAR_INSTANCE_DATA, inst.compile(["wght", "wdth"]))
|
||||||
|
|
||||||
|
def test_decompile(self):
|
||||||
|
inst = NamedInstance()
|
||||||
|
inst.decompile(FVAR_INSTANCE_DATA, ["wght", "wdth"])
|
||||||
|
self.assertEqual(345, inst.nameID)
|
||||||
|
self.assertEqual(0x1234, inst.flags)
|
||||||
|
self.assertEqual({"wght": 0.7, "wdth": 0.5}, inst.coordinates)
|
||||||
|
|
||||||
|
def test_toXML(self):
|
||||||
|
font = MakeFont()
|
||||||
|
inst = NamedInstance()
|
||||||
|
inst.nameID = AddName(font, "Light Condensed").nameID
|
||||||
|
inst.flags = 0x1234
|
||||||
|
inst.coordinates = {"wght": 0.7, "wdth": 0.5}
|
||||||
|
writer = XMLWriter(StringIO())
|
||||||
|
inst.toXML(writer, font)
|
||||||
|
self.assertEqual([
|
||||||
|
'',
|
||||||
|
'<!-- Light Condensed -->',
|
||||||
|
'<NamedInstance flags="00010010 00110100" nameID="%s">' % inst.nameID,
|
||||||
|
'<coord axis="wght" value="0.7"/>',
|
||||||
|
'<coord axis="wdth" value="0.5"/>',
|
||||||
|
'</NamedInstance>'
|
||||||
|
], xml_lines(writer))
|
||||||
|
|
||||||
|
def test_fromXML(self):
|
||||||
|
inst = NamedInstance()
|
||||||
|
attrs = {"flags": "00010010 00110100", "nameID": "345"}
|
||||||
|
inst.fromXML("NamedInstance", attrs, [
|
||||||
|
("coord", {"axis": "wght", "value": "0.7"}, []),
|
||||||
|
("coord", {"axis": "wdth", "value": "0.5"}, []),
|
||||||
|
], ttFont=MakeFont())
|
||||||
|
self.assertEqual(0x1234, inst.flags)
|
||||||
|
self.assertEqual(345, inst.nameID)
|
||||||
|
self.assertEqual({"wght": 0.7, "wdth": 0.5}, inst.coordinates)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
unittest.main()
|
@ -52,7 +52,7 @@ class table__g_v_a_r(DefaultTable.DefaultTable):
|
|||||||
dependencies = ["fvar", "glyf"]
|
dependencies = ["fvar", "glyf"]
|
||||||
|
|
||||||
def compile(self, ttFont):
|
def compile(self, ttFont):
|
||||||
axisTags = [axis.AxisTag for axis in ttFont["fvar"].table.VariationAxis]
|
axisTags = [axis.axisTag for axis in ttFont["fvar"].axes]
|
||||||
|
|
||||||
sharedCoords = self.compileSharedCoords_(axisTags)
|
sharedCoords = self.compileSharedCoords_(axisTags)
|
||||||
sharedCoordIndices = {coord:i for i, coord in enumerate(sharedCoords)}
|
sharedCoordIndices = {coord:i for i, coord in enumerate(sharedCoords)}
|
||||||
@ -168,7 +168,7 @@ class table__g_v_a_r(DefaultTable.DefaultTable):
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
def decompile(self, data, ttFont):
|
def decompile(self, data, ttFont):
|
||||||
axisTags = [axis.AxisTag for axis in ttFont["fvar"].table.VariationAxis]
|
axisTags = [axis.axisTag for axis in ttFont["fvar"].axes]
|
||||||
glyphs = ttFont.getGlyphOrder()
|
glyphs = ttFont.getGlyphOrder()
|
||||||
sstruct.unpack(GVAR_HEADER_FORMAT, data[0:GVAR_HEADER_SIZE], self)
|
sstruct.unpack(GVAR_HEADER_FORMAT, data[0:GVAR_HEADER_SIZE], self)
|
||||||
assert len(glyphs) == self.glyphCount
|
assert len(glyphs) == self.glyphCount
|
||||||
@ -301,7 +301,7 @@ class table__g_v_a_r(DefaultTable.DefaultTable):
|
|||||||
writer.newline()
|
writer.newline()
|
||||||
writer.simpletag("reserved", value=self.reserved)
|
writer.simpletag("reserved", value=self.reserved)
|
||||||
writer.newline()
|
writer.newline()
|
||||||
axisTags = [axis.AxisTag for axis in ttFont["fvar"].table.VariationAxis]
|
axisTags = [axis.axisTag for axis in ttFont["fvar"].axes]
|
||||||
for glyphName in ttFont.getGlyphOrder():
|
for glyphName in ttFont.getGlyphOrder():
|
||||||
variations = self.variations.get(glyphName)
|
variations = self.variations.get(glyphName)
|
||||||
if not variations:
|
if not variations:
|
||||||
|
@ -1020,39 +1020,4 @@ otData = [
|
|||||||
('uint16', 'SettingNameID', None, None, 'The name table index for the setting name.'),
|
('uint16', 'SettingNameID', None, None, 'The name table index for the setting name.'),
|
||||||
]),
|
]),
|
||||||
|
|
||||||
##
|
|
||||||
## Apple TrueType GX tables
|
|
||||||
##
|
|
||||||
|
|
||||||
#
|
|
||||||
# fvar
|
|
||||||
#
|
|
||||||
|
|
||||||
('fvar', [
|
|
||||||
('Version', 'Version', None, None, 'Version of the fvar table-initially set to 0x00010000.'),
|
|
||||||
('uint16', 'OffsetToData', None, None, 'Set to 16.'),
|
|
||||||
('uint16', 'CountSizePairs', None, None, 'Set to 2.'),
|
|
||||||
('uint16', 'AxisCount', None, None, 'Number of style axes in this font.'),
|
|
||||||
('uint16', 'AxisSize', None, None, 'Set to 20.'),
|
|
||||||
('uint16', 'InstanceCount', None, None, 'Number of named instances in this font.'),
|
|
||||||
('uint16', 'InstanceSize', None, None, 'Number of bytes in each instance.'),
|
|
||||||
('VariationAxis', 'VariationAxis', 'AxisCount', 0, 'The variation axes array.'),
|
|
||||||
('NamedInstance', 'NamedInstance', 'InstanceCount', 0, 'The named instances array.'),
|
|
||||||
]),
|
|
||||||
|
|
||||||
('VariationAxis', [
|
|
||||||
('Tag', 'AxisTag', None, None, '4-byte AxisTag identifier'),
|
|
||||||
('Fixed', 'MinValue', None, None, 'The minimum style coordinate for the axis.'),
|
|
||||||
('Fixed', 'DefaultValue', None, None, 'The default style coordinate for the axis.'),
|
|
||||||
('Fixed', 'MaxValue', None, None, 'The maximum style coordinate for the axis.'),
|
|
||||||
('uint16', 'Flags', None, None, 'Set to zero.'),
|
|
||||||
('uint16', 'NameID', None, None, 'The name table index for the setting name.'),
|
|
||||||
]),
|
|
||||||
|
|
||||||
('NamedInstance', [
|
|
||||||
('uint16', 'NameID', None, None, 'The name table index for the instance name.'),
|
|
||||||
('uint16', 'Flags', None, None, 'Set to zero.'),
|
|
||||||
('Fixed', 'Coords', 'AxisCount', 0, 'The maximum style coordinate for the axis.'),
|
|
||||||
]),
|
|
||||||
|
|
||||||
]
|
]
|
||||||
|
Loading…
x
Reference in New Issue
Block a user