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