2017-09-13 23:39:39 +07:00
|
|
|
from __future__ import print_function, division, absolute_import
|
|
|
|
from fontTools.misc.py23 import *
|
|
|
|
from fontTools.misc import sstruct
|
|
|
|
from fontTools.misc.textTools import safeEval
|
|
|
|
from .otBase import BaseTTXConverter
|
|
|
|
from . import DefaultTable
|
|
|
|
from . import grUtils
|
|
|
|
import struct
|
|
|
|
|
|
|
|
Feat_hdr_format='''
|
|
|
|
>
|
|
|
|
version: 16.16F
|
|
|
|
'''
|
|
|
|
|
|
|
|
class table_F__e_a_t(DefaultTable.DefaultTable):
|
|
|
|
|
|
|
|
def __init__(self, tag=None):
|
|
|
|
DefaultTable.DefaultTable.__init__(self, tag)
|
|
|
|
self.features = {}
|
|
|
|
|
|
|
|
def decompile(self, data, ttFont):
|
|
|
|
(_, data) = sstruct.unpack2(Feat_hdr_format, data, self)
|
|
|
|
numFeats, = struct.unpack('>H', data[:2])
|
|
|
|
data = data[8:]
|
|
|
|
allfeats = []
|
|
|
|
maxsetting = 0
|
|
|
|
for i in range(numFeats):
|
2017-09-14 16:47:01 +07:00
|
|
|
if self.version >= 2.0:
|
|
|
|
(fid, nums, _, offset, flags, lid) = struct.unpack(">LHHLHH",
|
2017-09-14 15:17:02 +07:00
|
|
|
data[16*i:16*(i+1)])
|
2017-09-14 16:47:01 +07:00
|
|
|
offset = int((offset - 12 - 16 * numFeats) / 4)
|
|
|
|
else:
|
|
|
|
(fid, nums, offset, flags, lid) = struct.unpack(">HHLHH",
|
|
|
|
data[12*i:12*(i+1)])
|
|
|
|
offset = int((offset - 12 - 12 * numFeats) / 4)
|
2017-09-13 23:39:39 +07:00
|
|
|
allfeats.append((fid, nums, offset, flags, lid))
|
|
|
|
maxsetting = max(maxsetting, offset + nums)
|
|
|
|
data = data[16*numFeats:]
|
|
|
|
allsettings = []
|
|
|
|
for i in range(maxsetting):
|
|
|
|
if len(data) >= 4 * (i + 1):
|
|
|
|
(val, lid) = struct.unpack(">HH", data[4*i:4*(i+1)])
|
|
|
|
allsettings.append((val, lid))
|
2017-11-03 23:21:02 +07:00
|
|
|
for i,f in enumerate(allfeats):
|
2017-09-13 23:39:39 +07:00
|
|
|
(fid, nums, offset, flags, lid) = f
|
|
|
|
fobj = Feature()
|
|
|
|
fobj.flags = flags
|
|
|
|
fobj.label = lid
|
|
|
|
self.features[grUtils.num2tag(fid)] = fobj
|
|
|
|
fobj.settings = {}
|
2017-11-03 23:21:02 +07:00
|
|
|
fobj.default = None
|
|
|
|
fobj.index = i
|
2017-09-13 23:39:39 +07:00
|
|
|
for i in range(offset, offset + nums):
|
|
|
|
if i >= len(allsettings): continue
|
|
|
|
(vid, vlid) = allsettings[i]
|
|
|
|
fobj.settings[vid] = vlid
|
2017-11-03 23:21:02 +07:00
|
|
|
if fobj.default is None:
|
|
|
|
fobj.default = vid
|
2017-09-13 23:39:39 +07:00
|
|
|
|
|
|
|
def compile(self, ttFont):
|
|
|
|
fdat = ""
|
|
|
|
vdat = ""
|
|
|
|
offset = 0
|
2017-11-03 23:21:02 +07:00
|
|
|
for f, v in sorted(self.features.items(), key=lambda x:x[1].index):
|
2017-09-15 11:18:44 +07:00
|
|
|
fnum = grUtils.tag2num(f)
|
2017-09-14 16:47:01 +07:00
|
|
|
if self.version >= 2.0:
|
|
|
|
fdat += struct.pack(">LHHLHH", grUtils.tag2num(f), len(v.settings),
|
|
|
|
0, offset * 4 + 12 + 16 * len(self.features), v.flags, v.label)
|
2017-09-15 11:18:44 +07:00
|
|
|
elif fnum > 65535: # self healing for alphabetic ids
|
|
|
|
self.version = 2.0
|
|
|
|
return self.compile(ttFont)
|
2017-09-14 16:47:01 +07:00
|
|
|
else:
|
|
|
|
fdat += struct.pack(">HHLHH", grUtils.tag2num(f), len(v.settings),
|
|
|
|
offset * 4 + 12 + 12 * len(self.features), v.flags, v.label)
|
2017-11-03 23:21:02 +07:00
|
|
|
for s, l in sorted(v.settings.items(), key=lambda x:(-1, x[1]) if x[0] == v.default else x):
|
2017-09-13 23:39:39 +07:00
|
|
|
vdat += struct.pack(">HH", s, l)
|
|
|
|
offset += len(v.settings)
|
|
|
|
hdr = sstruct.pack(Feat_hdr_format, self)
|
|
|
|
return hdr + struct.pack('>HHL', len(self.features), 0, 0) + fdat + vdat
|
|
|
|
|
|
|
|
def toXML(self, writer, ttFont):
|
|
|
|
writer.simpletag('version', version=self.version)
|
|
|
|
writer.newline()
|
2017-11-03 23:21:02 +07:00
|
|
|
for f, v in sorted(self.features.items(), key=lambda x:x[1].index):
|
|
|
|
writer.begintag('feature', fid=f, label=v.label, flags=v.flags,
|
|
|
|
default=(v.default if v.default else 0))
|
2017-09-13 23:39:39 +07:00
|
|
|
writer.newline()
|
|
|
|
for s, l in sorted(v.settings.items()):
|
|
|
|
writer.simpletag('setting', value=s, label=l)
|
|
|
|
writer.newline()
|
|
|
|
writer.endtag('feature')
|
|
|
|
writer.newline()
|
|
|
|
|
|
|
|
def fromXML(self, name, attrs, content, ttFont):
|
|
|
|
if name == 'version':
|
|
|
|
self.version = float(safeEval(attrs['version']))
|
|
|
|
elif name == 'feature':
|
|
|
|
fid = attrs['fid']
|
|
|
|
fobj = Feature()
|
|
|
|
fobj.flags = int(safeEval(attrs['flags']))
|
|
|
|
fobj.label = int(safeEval(attrs['label']))
|
2017-11-04 00:34:47 +07:00
|
|
|
fobj.default = int(safeEval(attrs.get('default','0')))
|
2017-11-03 23:21:02 +07:00
|
|
|
fobj.index = len(self.features)
|
2017-09-13 23:39:39 +07:00
|
|
|
self.features[fid] = fobj
|
|
|
|
fobj.settings = {}
|
|
|
|
for element in content:
|
|
|
|
if not isinstance(element, tuple): continue
|
|
|
|
tag, a, c = element
|
|
|
|
if tag == 'setting':
|
|
|
|
fobj.settings[int(safeEval(a['value']))] = int(safeEval(a['label']))
|
|
|
|
|
|
|
|
class Feature(object):
|
|
|
|
pass
|
|
|
|
|