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