Coverage for /usr/lib/python3/dist-packages/fontTools/varLib/builder.py: 18%
91 statements
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 15:55 +0200
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-14 15:55 +0200
1from fontTools import ttLib
2from fontTools.ttLib.tables import otTables as ot
4# VariationStore
7def buildVarRegionAxis(axisSupport):
8 self = ot.VarRegionAxis()
9 self.StartCoord, self.PeakCoord, self.EndCoord = [float(v) for v in axisSupport]
10 return self
13def buildVarRegion(support, axisTags):
14 assert all(tag in axisTags for tag in support.keys()), (
15 "Unknown axis tag found.",
16 support,
17 axisTags,
18 )
19 self = ot.VarRegion()
20 self.VarRegionAxis = []
21 for tag in axisTags:
22 self.VarRegionAxis.append(buildVarRegionAxis(support.get(tag, (0, 0, 0))))
23 return self
26def buildVarRegionList(supports, axisTags):
27 self = ot.VarRegionList()
28 self.RegionAxisCount = len(axisTags)
29 self.Region = []
30 for support in supports:
31 self.Region.append(buildVarRegion(support, axisTags))
32 self.RegionCount = len(self.Region)
33 return self
36def _reorderItem(lst, mapping):
37 return [lst[i] for i in mapping]
40def VarData_calculateNumShorts(self, optimize=False):
41 count = self.VarRegionCount
42 items = self.Item
43 bit_lengths = [0] * count
44 for item in items:
45 # The "+ (i < -1)" magic is to handle two's-compliment.
46 # That is, we want to get back 7 for -128, whereas
47 # bit_length() returns 8. Similarly for -65536.
48 # The reason "i < -1" is used instead of "i < 0" is that
49 # the latter would make it return 0 for "-1" instead of 1.
50 bl = [(i + (i < -1)).bit_length() for i in item]
51 bit_lengths = [max(*pair) for pair in zip(bl, bit_lengths)]
52 # The addition of 8, instead of seven, is to account for the sign bit.
53 # This "((b + 8) >> 3) if b else 0" when combined with the above
54 # "(i + (i < -1)).bit_length()" is a faster way to compute byte-lengths
55 # conforming to:
56 #
57 # byte_length = (0 if i == 0 else
58 # 1 if -128 <= i < 128 else
59 # 2 if -65536 <= i < 65536 else
60 # ...)
61 byte_lengths = [((b + 8) >> 3) if b else 0 for b in bit_lengths]
63 # https://github.com/fonttools/fonttools/issues/2279
64 longWords = any(b > 2 for b in byte_lengths)
66 if optimize:
67 # Reorder columns such that wider columns come before narrower columns
68 mapping = []
69 mapping.extend(i for i, b in enumerate(byte_lengths) if b > 2)
70 mapping.extend(i for i, b in enumerate(byte_lengths) if b == 2)
71 mapping.extend(i for i, b in enumerate(byte_lengths) if b == 1)
73 byte_lengths = _reorderItem(byte_lengths, mapping)
74 self.VarRegionIndex = _reorderItem(self.VarRegionIndex, mapping)
75 self.VarRegionCount = len(self.VarRegionIndex)
76 for i in range(len(items)):
77 items[i] = _reorderItem(items[i], mapping)
79 if longWords:
80 self.NumShorts = (
81 max((i for i, b in enumerate(byte_lengths) if b > 2), default=-1) + 1
82 )
83 self.NumShorts |= 0x8000
84 else:
85 self.NumShorts = (
86 max((i for i, b in enumerate(byte_lengths) if b > 1), default=-1) + 1
87 )
89 self.VarRegionCount = len(self.VarRegionIndex)
90 return self
93ot.VarData.calculateNumShorts = VarData_calculateNumShorts
96def VarData_CalculateNumShorts(self, optimize=True):
97 """Deprecated name for VarData_calculateNumShorts() which
98 defaults to optimize=True. Use varData.calculateNumShorts()
99 or varData.optimize()."""
100 return VarData_calculateNumShorts(self, optimize=optimize)
103def VarData_optimize(self):
104 return VarData_calculateNumShorts(self, optimize=True)
107ot.VarData.optimize = VarData_optimize
110def buildVarData(varRegionIndices, items, optimize=True):
111 self = ot.VarData()
112 self.VarRegionIndex = list(varRegionIndices)
113 regionCount = self.VarRegionCount = len(self.VarRegionIndex)
114 records = self.Item = []
115 if items:
116 for item in items:
117 assert len(item) == regionCount
118 records.append(list(item))
119 self.ItemCount = len(self.Item)
120 self.calculateNumShorts(optimize=optimize)
121 return self
124def buildVarStore(varRegionList, varDataList):
125 self = ot.VarStore()
126 self.Format = 1
127 self.VarRegionList = varRegionList
128 self.VarData = list(varDataList)
129 self.VarDataCount = len(self.VarData)
130 return self
133# Variation helpers
136def buildVarIdxMap(varIdxes, glyphOrder):
137 self = ot.VarIdxMap()
138 self.mapping = {g: v for g, v in zip(glyphOrder, varIdxes)}
139 return self
142def buildDeltaSetIndexMap(varIdxes):
143 mapping = list(varIdxes)
144 if all(i == v for i, v in enumerate(mapping)):
145 return None
146 self = ot.DeltaSetIndexMap()
147 self.mapping = mapping
148 self.Format = 1 if len(mapping) > 0xFFFF else 0
149 return self
152def buildVarDevTable(varIdx):
153 self = ot.Device()
154 self.DeltaFormat = 0x8000
155 self.StartSize = varIdx >> 16
156 self.EndSize = varIdx & 0xFFFF
157 return self