1from fontTools.misc.py23 import bytesjoin 2from fontTools.misc import sstruct 3from fontTools.misc.fixedTools import ( 4 fixedToFloat as fi2fl, 5 floatToFixed as fl2fi, 6 floatToFixedToStr as fl2str, 7 strToFixedToFloat as str2fl, 8) 9from fontTools.ttLib import TTLibError 10from . import DefaultTable 11import struct 12import logging 13 14 15log = logging.getLogger(__name__) 16 17# Apple's documentation of 'avar': 18# https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6avar.html 19 20AVAR_HEADER_FORMAT = """ 21 > # big endian 22 majorVersion: H 23 minorVersion: H 24 reserved: H 25 axisCount: H 26""" 27assert sstruct.calcsize(AVAR_HEADER_FORMAT) == 8, sstruct.calcsize(AVAR_HEADER_FORMAT) 28 29 30class table__a_v_a_r(DefaultTable.DefaultTable): 31 32 dependencies = ["fvar"] 33 34 def __init__(self, tag=None): 35 DefaultTable.DefaultTable.__init__(self, tag) 36 self.segments = {} 37 38 def compile(self, ttFont): 39 axisTags = [axis.axisTag for axis in ttFont["fvar"].axes] 40 header = { 41 "majorVersion": 1, 42 "minorVersion": 0, 43 "reserved": 0, 44 "axisCount": len(axisTags) 45 } 46 result = [sstruct.pack(AVAR_HEADER_FORMAT, header)] 47 for axis in axisTags: 48 mappings = sorted(self.segments[axis].items()) 49 result.append(struct.pack(">H", len(mappings))) 50 for key, value in mappings: 51 fixedKey = fl2fi(key, 14) 52 fixedValue = fl2fi(value, 14) 53 result.append(struct.pack(">hh", fixedKey, fixedValue)) 54 return bytesjoin(result) 55 56 def decompile(self, data, ttFont): 57 axisTags = [axis.axisTag for axis in ttFont["fvar"].axes] 58 header = {} 59 headerSize = sstruct.calcsize(AVAR_HEADER_FORMAT) 60 header = sstruct.unpack(AVAR_HEADER_FORMAT, data[0:headerSize]) 61 majorVersion = header["majorVersion"] 62 if majorVersion != 1: 63 raise TTLibError("unsupported 'avar' version %d" % majorVersion) 64 pos = headerSize 65 for axis in axisTags: 66 segments = self.segments[axis] = {} 67 numPairs = struct.unpack(">H", data[pos:pos+2])[0] 68 pos = pos + 2 69 for _ in range(numPairs): 70 fromValue, toValue = struct.unpack(">hh", data[pos:pos+4]) 71 segments[fi2fl(fromValue, 14)] = fi2fl(toValue, 14) 72 pos = pos + 4 73 74 def toXML(self, writer, ttFont): 75 axisTags = [axis.axisTag for axis in ttFont["fvar"].axes] 76 for axis in axisTags: 77 writer.begintag("segment", axis=axis) 78 writer.newline() 79 for key, value in sorted(self.segments[axis].items()): 80 key = fl2str(key, 14) 81 value = fl2str(value, 14) 82 writer.simpletag("mapping", **{"from": key, "to": value}) 83 writer.newline() 84 writer.endtag("segment") 85 writer.newline() 86 87 def fromXML(self, name, attrs, content, ttFont): 88 if name == "segment": 89 axis = attrs["axis"] 90 segment = self.segments[axis] = {} 91 for element in content: 92 if isinstance(element, tuple): 93 elementName, elementAttrs, _ = element 94 if elementName == "mapping": 95 fromValue = str2fl(elementAttrs["from"], 14) 96 toValue = str2fl(elementAttrs["to"], 14) 97 if fromValue in segment: 98 log.warning("duplicate entry for %s in axis '%s'", 99 fromValue, axis) 100 segment[fromValue] = toValue 101