blob: c223c815881979e15ed44561eb66bfed9be1de3b [file] [log] [blame]
from __future__ import print_function, division, absolute_import, unicode_literals
from fontTools.misc.py23 import *
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')
# 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)
}
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
def setUp(self):
table = table__t_r_a_k()
table.version = 1.0
table.format = 0
self.font = {'trak': table}
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)
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)
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)
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)
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)
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())
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)
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)
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)
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())
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)
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)
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))
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))
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))
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
sys.exit(unittest.main())