• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1from __future__ import print_function, division, absolute_import
2from fontTools.misc.py23 import *
3from fontTools.misc import sstruct
4from fontTools.misc.textTools import safeEval
5from .otBase import BaseTTXConverter
6from . import DefaultTable
7from . import grUtils
8import struct
9
10Feat_hdr_format='''
11    >
12    version:    16.16F
13'''
14
15class table_F__e_a_t(DefaultTable.DefaultTable):
16
17    def __init__(self, tag=None):
18        DefaultTable.DefaultTable.__init__(self, tag)
19        self.features = {}
20
21    def decompile(self, data, ttFont):
22        (_, data) = sstruct.unpack2(Feat_hdr_format, data, self)
23        numFeats, = struct.unpack('>H', data[:2])
24        data = data[8:]
25        allfeats = []
26        maxsetting = 0
27        for i in range(numFeats):
28            if self.version >= 2.0:
29                (fid, nums, _, offset, flags, lid) = struct.unpack(">LHHLHH",
30                                                            data[16*i:16*(i+1)])
31                offset = int((offset - 12 - 16 * numFeats) / 4)
32            else:
33                (fid, nums, offset, flags, lid) = struct.unpack(">HHLHH",
34                                                            data[12*i:12*(i+1)])
35                offset = int((offset - 12 - 12 * numFeats) / 4)
36            allfeats.append((fid, nums, offset, flags, lid))
37            maxsetting = max(maxsetting, offset + nums)
38        data = data[16*numFeats:]
39        allsettings = []
40        for i in range(maxsetting):
41            if len(data) >= 4 * (i + 1):
42                (val, lid) = struct.unpack(">HH", data[4*i:4*(i+1)])
43                allsettings.append((val, lid))
44        for i,f in enumerate(allfeats):
45            (fid, nums, offset, flags, lid) = f
46            fobj = Feature()
47            fobj.flags = flags
48            fobj.label = lid
49            self.features[grUtils.num2tag(fid)] = fobj
50            fobj.settings = {}
51            fobj.default = None
52            fobj.index = i
53            for i in range(offset, offset + nums):
54                if i >= len(allsettings): continue
55                (vid, vlid) = allsettings[i]
56                fobj.settings[vid] = vlid
57                if fobj.default is None:
58                    fobj.default = vid
59
60    def compile(self, ttFont):
61        fdat = b""
62        vdat = b""
63        offset = 0
64        for f, v in sorted(self.features.items(), key=lambda x:x[1].index):
65            fnum = grUtils.tag2num(f)
66            if self.version >= 2.0:
67                fdat += struct.pack(">LHHLHH", grUtils.tag2num(f), len(v.settings),
68                    0, offset * 4 + 12 + 16 * len(self.features), v.flags, v.label)
69            elif fnum > 65535:      # self healing for alphabetic ids
70                self.version = 2.0
71                return self.compile(ttFont)
72            else:
73                fdat += struct.pack(">HHLHH", grUtils.tag2num(f), len(v.settings),
74                    offset * 4 + 12 + 12 * len(self.features), v.flags, v.label)
75            for s, l in sorted(v.settings.items(), key=lambda x:(-1, x[1]) if x[0] == v.default else x):
76                vdat += struct.pack(">HH", s, l)
77            offset += len(v.settings)
78        hdr = sstruct.pack(Feat_hdr_format, self)
79        return hdr + struct.pack('>HHL', len(self.features), 0, 0) + fdat + vdat
80
81    def toXML(self, writer, ttFont):
82        writer.simpletag('version', version=self.version)
83        writer.newline()
84        for f, v in sorted(self.features.items(), key=lambda x:x[1].index):
85            writer.begintag('feature', fid=f, label=v.label, flags=v.flags,
86                            default=(v.default if v.default else 0))
87            writer.newline()
88            for s, l in sorted(v.settings.items()):
89                writer.simpletag('setting', value=s, label=l)
90                writer.newline()
91            writer.endtag('feature')
92            writer.newline()
93
94    def fromXML(self, name, attrs, content, ttFont):
95        if name == 'version':
96            self.version = float(safeEval(attrs['version']))
97        elif name == 'feature':
98            fid = attrs['fid']
99            fobj = Feature()
100            fobj.flags = int(safeEval(attrs['flags']))
101            fobj.label = int(safeEval(attrs['label']))
102            fobj.default = int(safeEval(attrs.get('default','0')))
103            fobj.index = len(self.features)
104            self.features[fid] = fobj
105            fobj.settings = {}
106            for element in content:
107                if not isinstance(element, tuple): continue
108                tag, a, c = element
109                if tag == 'setting':
110                    fobj.settings[int(safeEval(a['value']))] = int(safeEval(a['label']))
111
112class Feature(object):
113    pass
114
115