fonttools/Tests/ttLib/tables/_t_r_a_k_test.py

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

344 lines
13 KiB
Python
Raw Normal View History

from fontTools.misc.testTools import parseXML, getXML
from fontTools.misc.textTools import deHexStr
from fontTools.ttLib import TTFont, TTLibError
from fontTools.ttLib.tables._t_r_a_k import *
from fontTools.ttLib.tables._n_a_m_e import table__n_a_m_e, NameRecord
import unittest
# /Library/Fonts/Osaka.ttf from OSX has trak table with both horiz and vertData
OSAKA_TRAK_TABLE_DATA = deHexStr(
"00 01 00 00 00 00 00 0c 00 40 00 00 00 03 00 02 00 00 00 2c ff ff "
"00 00 01 06 00 34 00 00 00 00 01 07 00 38 00 01 00 00 01 08 00 3c "
"00 0c 00 00 00 18 00 00 ff f4 ff f4 00 00 00 00 00 0c 00 0c 00 03 "
"00 02 00 00 00 60 ff ff 00 00 01 09 00 68 00 00 00 00 01 0a 00 6c "
"00 01 00 00 01 0b 00 70 00 0c 00 00 00 18 00 00 ff f4 ff f4 00 00 "
"00 00 00 0c 00 0c"
)
2022-12-13 11:26:36 +00:00
# decompiled horizData and vertData entries from Osaka.ttf
OSAKA_HORIZ_TRACK_ENTRIES = {
-1.0: TrackTableEntry({24.0: -12, 12.0: -12}, nameIndex=262),
0.0: TrackTableEntry({24.0: 0, 12.0: 0}, nameIndex=263),
1.0: TrackTableEntry({24.0: 12, 12.0: 12}, nameIndex=264),
}
OSAKA_VERT_TRACK_ENTRIES = {
-1.0: TrackTableEntry({24.0: -12, 12.0: -12}, nameIndex=265),
0.0: TrackTableEntry({24.0: 0, 12.0: 0}, nameIndex=266),
1.0: TrackTableEntry({24.0: 12, 12.0: 12}, nameIndex=267),
}
OSAKA_TRAK_TABLE_XML = [
'<version value="1.0"/>',
'<format value="0"/>',
"<horizData>",
" <!-- nTracks=3, nSizes=2 -->",
' <trackEntry value="-1.0" nameIndex="262">',
" <!-- Tight -->",
' <track size="12.0" value="-12"/>',
' <track size="24.0" value="-12"/>',
" </trackEntry>",
' <trackEntry value="0.0" nameIndex="263">',
" <!-- Normal -->",
' <track size="12.0" value="0"/>',
' <track size="24.0" value="0"/>',
" </trackEntry>",
' <trackEntry value="1.0" nameIndex="264">',
" <!-- Loose -->",
' <track size="12.0" value="12"/>',
' <track size="24.0" value="12"/>',
" </trackEntry>",
"</horizData>",
"<vertData>",
" <!-- nTracks=3, nSizes=2 -->",
' <trackEntry value="-1.0" nameIndex="265">',
" <!-- Tight -->",
' <track size="12.0" value="-12"/>',
' <track size="24.0" value="-12"/>',
" </trackEntry>",
' <trackEntry value="0.0" nameIndex="266">',
" <!-- Normal -->",
' <track size="12.0" value="0"/>',
' <track size="24.0" value="0"/>',
" </trackEntry>",
' <trackEntry value="1.0" nameIndex="267">',
" <!-- Loose -->",
' <track size="12.0" value="12"/>',
' <track size="24.0" value="12"/>',
" </trackEntry>",
"</vertData>",
]
# made-up table containing only vertData (no horizData)
OSAKA_VERT_ONLY_TRAK_TABLE_DATA = deHexStr(
"00 01 00 00 00 00 00 00 00 0c 00 00 00 03 00 02 00 00 00 2c ff ff "
"00 00 01 09 00 34 00 00 00 00 01 0a 00 38 00 01 00 00 01 0b 00 3c "
"00 0c 00 00 00 18 00 00 ff f4 ff f4 00 00 00 00 00 0c 00 0c"
)
OSAKA_VERT_ONLY_TRAK_TABLE_XML = [
'<version value="1.0"/>',
'<format value="0"/>',
"<horizData>",
" <!-- nTracks=0, nSizes=0 -->",
"</horizData>",
"<vertData>",
" <!-- nTracks=3, nSizes=2 -->",
' <trackEntry value="-1.0" nameIndex="265">',
" <!-- Tight -->",
' <track size="12.0" value="-12"/>',
' <track size="24.0" value="-12"/>',
" </trackEntry>",
' <trackEntry value="0.0" nameIndex="266">',
" <!-- Normal -->",
' <track size="12.0" value="0"/>',
' <track size="24.0" value="0"/>',
" </trackEntry>",
' <trackEntry value="1.0" nameIndex="267">',
" <!-- Loose -->",
' <track size="12.0" value="12"/>',
' <track size="24.0" value="12"/>',
" </trackEntry>",
"</vertData>",
]
# also /Library/Fonts/Skia.ttf contains a trak table with horizData
SKIA_TRAK_TABLE_DATA = deHexStr(
"00 01 00 00 00 00 00 0c 00 00 00 00 00 03 00 05 00 00 00 2c ff ff "
"00 00 01 13 00 40 00 00 00 00 01 2f 00 4a 00 01 00 00 01 14 00 54 "
"00 09 00 00 00 0a 00 00 00 0c 00 00 00 12 00 00 00 13 00 00 ff f6 "
"ff e2 ff c4 ff c1 ff c1 00 0f 00 00 ff fb ff e7 ff e7 00 8c 00 82 "
"00 7d 00 73 00 73"
)
SKIA_TRACK_ENTRIES = {
-1.0: TrackTableEntry(
{9.0: -10, 10.0: -30, 19.0: -63, 12.0: -60, 18.0: -63}, nameIndex=275
),
0.0: TrackTableEntry(
{9.0: 15, 10.0: 0, 19.0: -25, 12.0: -5, 18.0: -25}, nameIndex=303
),
1.0: TrackTableEntry(
{9.0: 140, 10.0: 130, 19.0: 115, 12.0: 125, 18.0: 115}, nameIndex=276
2022-12-13 11:26:36 +00:00
),
}
SKIA_TRAK_TABLE_XML = [
'<version value="1.0"/>',
'<format value="0"/>',
"<horizData>",
" <!-- nTracks=3, nSizes=5 -->",
' <trackEntry value="-1.0" nameIndex="275">',
" <!-- Tight -->",
' <track size="9.0" value="-10"/>',
' <track size="10.0" value="-30"/>',
' <track size="12.0" value="-60"/>',
' <track size="18.0" value="-63"/>',
' <track size="19.0" value="-63"/>',
" </trackEntry>",
' <trackEntry value="0.0" nameIndex="303">',
" <!-- Normal -->",
' <track size="9.0" value="15"/>',
' <track size="10.0" value="0"/>',
' <track size="12.0" value="-5"/>',
' <track size="18.0" value="-25"/>',
' <track size="19.0" value="-25"/>',
" </trackEntry>",
' <trackEntry value="1.0" nameIndex="276">',
" <!-- Loose -->",
' <track size="9.0" value="140"/>',
' <track size="10.0" value="130"/>',
' <track size="12.0" value="125"/>',
' <track size="18.0" value="115"/>',
' <track size="19.0" value="115"/>',
" </trackEntry>",
"</horizData>",
"<vertData>",
" <!-- nTracks=0, nSizes=0 -->",
"</vertData>",
]
class TrackingTableTest(unittest.TestCase):
def __init__(self, methodName):
unittest.TestCase.__init__(self, methodName)
# Python 3 renamed assertRaisesRegexp to assertRaisesRegex,
# and fires deprecation warnings if a program uses the old name.
if not hasattr(self, "assertRaisesRegex"):
self.assertRaisesRegex = self.assertRaisesRegexp
2022-12-13 11:26:36 +00:00
def setUp(self):
table = table__t_r_a_k()
table.version = 1.0
table.format = 0
self.font = {"trak": table}
2022-12-13 11:26:36 +00:00
def test_compile_horiz(self):
table = self.font["trak"]
table.horizData = TrackData(SKIA_TRACK_ENTRIES)
trakData = table.compile(self.font)
self.assertEqual(trakData, SKIA_TRAK_TABLE_DATA)
2022-12-13 11:26:36 +00:00
def test_compile_vert(self):
table = self.font["trak"]
table.vertData = TrackData(OSAKA_VERT_TRACK_ENTRIES)
trakData = table.compile(self.font)
self.assertEqual(trakData, OSAKA_VERT_ONLY_TRAK_TABLE_DATA)
2022-12-13 11:26:36 +00:00
def test_compile_horiz_and_vert(self):
table = self.font["trak"]
table.horizData = TrackData(OSAKA_HORIZ_TRACK_ENTRIES)
table.vertData = TrackData(OSAKA_VERT_TRACK_ENTRIES)
trakData = table.compile(self.font)
self.assertEqual(trakData, OSAKA_TRAK_TABLE_DATA)
2022-12-13 11:26:36 +00:00
def test_compile_longword_aligned(self):
table = self.font["trak"]
# without padding, this 'horizData' would end up 46 byte long
table.horizData = TrackData(
{0.0: TrackTableEntry(nameIndex=256, values={12.0: 0, 24.0: 0, 36.0: 0})}
)
table.vertData = TrackData(
{0.0: TrackTableEntry(nameIndex=257, values={12.0: 0, 24.0: 0, 36.0: 0})}
)
trakData = table.compile(self.font)
self.assertTrue(table.vertOffset % 4 == 0)
2022-12-13 11:26:36 +00:00
def test_compile_sizes_mismatch(self):
table = self.font["trak"]
table.horizData = TrackData(
{
-1.0: TrackTableEntry(nameIndex=256, values={9.0: -10, 10.0: -30}),
0.0: TrackTableEntry(nameIndex=257, values={8.0: 20, 12.0: 0}),
}
)
with self.assertRaisesRegex(TTLibError, "entries must specify the same sizes"):
table.compile(self.font)
2022-12-13 11:26:36 +00:00
def test_decompile_horiz(self):
table = self.font["trak"]
table.decompile(SKIA_TRAK_TABLE_DATA, self.font)
self.assertEqual(table.horizData, SKIA_TRACK_ENTRIES)
self.assertEqual(table.vertData, TrackData())
2022-12-13 11:26:36 +00:00
def test_decompile_vert(self):
table = self.font["trak"]
table.decompile(OSAKA_VERT_ONLY_TRAK_TABLE_DATA, self.font)
self.assertEqual(table.horizData, TrackData())
self.assertEqual(table.vertData, OSAKA_VERT_TRACK_ENTRIES)
2022-12-13 11:26:36 +00:00
def test_decompile_horiz_and_vert(self):
table = self.font["trak"]
table.decompile(OSAKA_TRAK_TABLE_DATA, self.font)
self.assertEqual(table.horizData, OSAKA_HORIZ_TRACK_ENTRIES)
self.assertEqual(table.vertData, OSAKA_VERT_TRACK_ENTRIES)
2022-12-13 11:26:36 +00:00
def test_roundtrip_decompile_compile(self):
for trakData in (
OSAKA_TRAK_TABLE_DATA,
OSAKA_VERT_ONLY_TRAK_TABLE_DATA,
SKIA_TRAK_TABLE_DATA,
):
table = table__t_r_a_k()
table.decompile(trakData, ttFont=None)
newTrakData = table.compile(ttFont=None)
self.assertEqual(trakData, newTrakData)
2022-12-13 11:26:36 +00:00
def test_fromXML_horiz(self):
table = self.font["trak"]
for name, attrs, content in parseXML(SKIA_TRAK_TABLE_XML):
table.fromXML(name, attrs, content, self.font)
self.assertEqual(table.version, 1.0)
self.assertEqual(table.format, 0)
self.assertEqual(table.horizData, SKIA_TRACK_ENTRIES)
self.assertEqual(table.vertData, TrackData())
2022-12-13 11:26:36 +00:00
def test_fromXML_horiz_and_vert(self):
table = self.font["trak"]
for name, attrs, content in parseXML(OSAKA_TRAK_TABLE_XML):
table.fromXML(name, attrs, content, self.font)
self.assertEqual(table.version, 1.0)
self.assertEqual(table.format, 0)
self.assertEqual(table.horizData, OSAKA_HORIZ_TRACK_ENTRIES)
self.assertEqual(table.vertData, OSAKA_VERT_TRACK_ENTRIES)
2022-12-13 11:26:36 +00:00
def test_fromXML_vert(self):
table = self.font["trak"]
for name, attrs, content in parseXML(OSAKA_VERT_ONLY_TRAK_TABLE_XML):
table.fromXML(name, attrs, content, self.font)
self.assertEqual(table.version, 1.0)
self.assertEqual(table.format, 0)
self.assertEqual(table.horizData, TrackData())
self.assertEqual(table.vertData, OSAKA_VERT_TRACK_ENTRIES)
2022-12-13 11:26:36 +00:00
def test_toXML_horiz(self):
table = self.font["trak"]
table.horizData = TrackData(SKIA_TRACK_ENTRIES)
add_name(self.font, "Tight", nameID=275)
add_name(self.font, "Normal", nameID=303)
add_name(self.font, "Loose", nameID=276)
self.assertEqual(SKIA_TRAK_TABLE_XML, getXML(table.toXML, self.font))
2022-12-13 11:26:36 +00:00
def test_toXML_horiz_and_vert(self):
table = self.font["trak"]
table.horizData = TrackData(OSAKA_HORIZ_TRACK_ENTRIES)
table.vertData = TrackData(OSAKA_VERT_TRACK_ENTRIES)
add_name(self.font, "Tight", nameID=262)
add_name(self.font, "Normal", nameID=263)
add_name(self.font, "Loose", nameID=264)
add_name(self.font, "Tight", nameID=265)
add_name(self.font, "Normal", nameID=266)
add_name(self.font, "Loose", nameID=267)
self.assertEqual(OSAKA_TRAK_TABLE_XML, getXML(table.toXML, self.font))
2022-12-13 11:26:36 +00:00
def test_toXML_vert(self):
table = self.font["trak"]
table.vertData = TrackData(OSAKA_VERT_TRACK_ENTRIES)
add_name(self.font, "Tight", nameID=265)
add_name(self.font, "Normal", nameID=266)
add_name(self.font, "Loose", nameID=267)
self.assertEqual(OSAKA_VERT_ONLY_TRAK_TABLE_XML, getXML(table.toXML, self.font))
2022-12-13 11:26:36 +00:00
def test_roundtrip_fromXML_toXML(self):
font = {}
add_name(font, "Tight", nameID=275)
add_name(font, "Normal", nameID=303)
add_name(font, "Loose", nameID=276)
add_name(font, "Tight", nameID=262)
add_name(font, "Normal", nameID=263)
add_name(font, "Loose", nameID=264)
add_name(font, "Tight", nameID=265)
add_name(font, "Normal", nameID=266)
add_name(font, "Loose", nameID=267)
for input_xml in (
SKIA_TRAK_TABLE_XML,
OSAKA_TRAK_TABLE_XML,
OSAKA_VERT_ONLY_TRAK_TABLE_XML,
):
table = table__t_r_a_k()
font["trak"] = table
for name, attrs, content in parseXML(input_xml):
table.fromXML(name, attrs, content, font)
output_xml = getXML(table.toXML, font)
self.assertEqual(input_xml, output_xml)
def add_name(font, string, nameID):
nameTable = font.get("name")
if nameTable is None:
nameTable = font["name"] = table__n_a_m_e()
nameTable.names = []
namerec = NameRecord()
namerec.nameID = nameID
namerec.string = string.encode("mac_roman")
namerec.platformID, namerec.platEncID, namerec.langID = (1, 0, 0)
nameTable.names.append(namerec)
if __name__ == "__main__":
import sys
2022-12-13 11:26:36 +00:00
sys.exit(unittest.main())