1from fontTools import ttLib 2from fontTools.ttLib.tables import otTables as ot 3 4# VariationStore 5 6def buildVarRegionAxis(axisSupport): 7 self = ot.VarRegionAxis() 8 self.StartCoord, self.PeakCoord, self.EndCoord = [float(v) for v in axisSupport] 9 return self 10 11def buildVarRegion(support, axisTags): 12 assert all(tag in axisTags for tag in support.keys()), ("Unknown axis tag found.", support, axisTags) 13 self = ot.VarRegion() 14 self.VarRegionAxis = [] 15 for tag in axisTags: 16 self.VarRegionAxis.append(buildVarRegionAxis(support.get(tag, (0,0,0)))) 17 return self 18 19def buildVarRegionList(supports, axisTags): 20 self = ot.VarRegionList() 21 self.RegionAxisCount = len(axisTags) 22 self.Region = [] 23 for support in supports: 24 self.Region.append(buildVarRegion(support, axisTags)) 25 self.RegionCount = len(self.Region) 26 return self 27 28 29def _reorderItem(lst, narrows, zeroes): 30 out = [] 31 count = len(lst) 32 for i in range(count): 33 if i not in narrows: 34 out.append(lst[i]) 35 for i in range(count): 36 if i in narrows and i not in zeroes: 37 out.append(lst[i]) 38 return out 39 40def VarData_calculateNumShorts(self, optimize=False): 41 count = self.VarRegionCount 42 items = self.Item 43 narrows = set(range(count)) 44 zeroes = set(range(count)) 45 for item in items: 46 wides = [i for i in narrows if not (-128 <= item[i] <= 127)] 47 narrows.difference_update(wides) 48 nonzeroes = [i for i in zeroes if item[i]] 49 zeroes.difference_update(nonzeroes) 50 if not narrows and not zeroes: 51 break 52 if optimize: 53 # Reorder columns such that all SHORT columns come before UINT8 54 self.VarRegionIndex = _reorderItem(self.VarRegionIndex, narrows, zeroes) 55 self.VarRegionCount = len(self.VarRegionIndex) 56 for i in range(len(items)): 57 items[i] = _reorderItem(items[i], narrows, zeroes) 58 self.NumShorts = count - len(narrows) 59 else: 60 wides = set(range(count)) - narrows 61 self.NumShorts = 1+max(wides) if wides else 0 62 self.VarRegionCount = len(self.VarRegionIndex) 63 return self 64 65ot.VarData.calculateNumShorts = VarData_calculateNumShorts 66 67def VarData_CalculateNumShorts(self, optimize=True): 68 """Deprecated name for VarData_calculateNumShorts() which 69 defaults to optimize=True. Use varData.calculateNumShorts() 70 or varData.optimize().""" 71 return VarData_calculateNumShorts(self, optimize=optimize) 72 73def VarData_optimize(self): 74 return VarData_calculateNumShorts(self, optimize=True) 75 76ot.VarData.optimize = VarData_optimize 77 78 79def buildVarData(varRegionIndices, items, optimize=True): 80 self = ot.VarData() 81 self.VarRegionIndex = list(varRegionIndices) 82 regionCount = self.VarRegionCount = len(self.VarRegionIndex) 83 records = self.Item = [] 84 if items: 85 for item in items: 86 assert len(item) == regionCount 87 records.append(list(item)) 88 self.ItemCount = len(self.Item) 89 self.calculateNumShorts(optimize=optimize) 90 return self 91 92 93def buildVarStore(varRegionList, varDataList): 94 self = ot.VarStore() 95 self.Format = 1 96 self.VarRegionList = varRegionList 97 self.VarData = list(varDataList) 98 self.VarDataCount = len(self.VarData) 99 return self 100 101 102# Variation helpers 103 104def buildVarIdxMap(varIdxes, glyphOrder): 105 self = ot.VarIdxMap() 106 self.mapping = {g:v for g,v in zip(glyphOrder, varIdxes)} 107 return self 108 109def buildVarDevTable(varIdx): 110 self = ot.Device() 111 self.DeltaFormat = 0x8000 112 self.StartSize = varIdx >> 16 113 self.EndSize = varIdx & 0xFFFF 114 return self 115