aboutsummaryrefslogtreecommitdiff
path: root/Lib/fontTools/varLib/builder.py
diff options
context:
space:
mode:
Diffstat (limited to 'Lib/fontTools/varLib/builder.py')
-rw-r--r--Lib/fontTools/varLib/builder.py71
1 files changed, 47 insertions, 24 deletions
diff --git a/Lib/fontTools/varLib/builder.py b/Lib/fontTools/varLib/builder.py
index 152336b0..60d7172e 100644
--- a/Lib/fontTools/varLib/builder.py
+++ b/Lib/fontTools/varLib/builder.py
@@ -26,39 +26,54 @@ def buildVarRegionList(supports, axisTags):
return self
-def _reorderItem(lst, narrows, zeroes):
- out = []
- count = len(lst)
- for i in range(count):
- if i not in narrows:
- out.append(lst[i])
- for i in range(count):
- if i in narrows and i not in zeroes:
- out.append(lst[i])
- return out
+def _reorderItem(lst, mapping):
+ return [lst[i] for i in mapping]
def VarData_calculateNumShorts(self, optimize=False):
count = self.VarRegionCount
items = self.Item
- narrows = set(range(count))
- zeroes = set(range(count))
+ bit_lengths = [0] * count
for item in items:
- wides = [i for i in narrows if not (-128 <= item[i] <= 127)]
- narrows.difference_update(wides)
- nonzeroes = [i for i in zeroes if item[i]]
- zeroes.difference_update(nonzeroes)
- if not narrows and not zeroes:
- break
+ # The "+ (i < -1)" magic is to handle two's-compliment.
+ # That is, we want to get back 7 for -128, whereas
+ # bit_length() returns 8. Similarly for -65536.
+ # The reason "i < -1" is used instead of "i < 0" is that
+ # the latter would make it return 0 for "-1" instead of 1.
+ bl = [(i + (i < -1)).bit_length() for i in item]
+ bit_lengths = [max(*pair) for pair in zip(bl, bit_lengths)]
+ # The addition of 8, instead of seven, is to account for the sign bit.
+ # This "((b + 8) >> 3) if b else 0" when combined with the above
+ # "(i + (i < -1)).bit_length()" is a faster way to compute byte-lengths
+ # conforming to:
+ #
+ # byte_length = (0 if i == 0 else
+ # 1 if -128 <= i < 128 else
+ # 2 if -65536 <= i < 65536 else
+ # ...)
+ byte_lengths = [((b + 8) >> 3) if b else 0 for b in bit_lengths]
+
+ # https://github.com/fonttools/fonttools/issues/2279
+ longWords = any(b > 2 for b in byte_lengths)
+
if optimize:
- # Reorder columns such that all SHORT columns come before UINT8
- self.VarRegionIndex = _reorderItem(self.VarRegionIndex, narrows, zeroes)
+ # Reorder columns such that wider columns come before narrower columns
+ mapping = []
+ mapping.extend(i for i,b in enumerate(byte_lengths) if b > 2)
+ mapping.extend(i for i,b in enumerate(byte_lengths) if b == 2)
+ mapping.extend(i for i,b in enumerate(byte_lengths) if b == 1)
+
+ byte_lengths = _reorderItem(byte_lengths, mapping)
+ self.VarRegionIndex = _reorderItem(self.VarRegionIndex, mapping)
self.VarRegionCount = len(self.VarRegionIndex)
for i in range(len(items)):
- items[i] = _reorderItem(items[i], narrows, zeroes)
- self.NumShorts = count - len(narrows)
+ items[i] = _reorderItem(items[i], mapping)
+
+ if longWords:
+ self.NumShorts = max((i for i,b in enumerate(byte_lengths) if b > 2), default=-1) + 1
+ self.NumShorts |= 0x8000
else:
- wides = set(range(count)) - narrows
- self.NumShorts = 1+max(wides) if wides else 0
+ self.NumShorts = max((i for i,b in enumerate(byte_lengths) if b > 1), default=-1) + 1
+
self.VarRegionCount = len(self.VarRegionIndex)
return self
@@ -106,6 +121,14 @@ def buildVarIdxMap(varIdxes, glyphOrder):
self.mapping = {g:v for g,v in zip(glyphOrder, varIdxes)}
return self
+
+def buildDeltaSetIndexMap(varIdxes):
+ self = ot.DeltaSetIndexMap()
+ self.mapping = list(varIdxes)
+ self.Format = 1 if len(varIdxes) > 0xFFFF else 0
+ return self
+
+
def buildVarDevTable(varIdx):
self = ot.Device()
self.DeltaFormat = 0x8000