def _SinglePosUpgradeToFormat2(self): if self.Format == 2: return self ret = ot.SinglePos() ret.Format = 2 ret.Coverage = self.Coverage ret.ValueFormat = self.ValueFormat ret.Value = [self.Value for _ in ret.Coverage.glyphs] ret.ValueCount = len(ret.Value) return ret
def buildSinglePosSubtable(values, glyphMap): """{glyphName: otBase.ValueRecord} --> otTables.SinglePos""" self = ot.SinglePos() self.Coverage = buildCoverage(values.keys(), glyphMap) valueRecords = [values[g] for g in self.Coverage.glyphs] self.ValueFormat = 0 for v in valueRecords: self.ValueFormat |= v.getFormat() if all(v == valueRecords[0] for v in valueRecords): self.Format = 1 if self.ValueFormat != 0: self.Value = valueRecords[0] else: self.Value = None else: self.Format = 2 self.Value = valueRecords self.ValueCount = len(self.Value) return self
def _Lookup_SinglePos_subtables_flatten(lst, font, min_inclusive_rec_format): glyphs, _ = _merge_GlyphOrders(font, [v.Coverage.glyphs for v in lst], None) num_glyphs = len(glyphs) new = ot.SinglePos() new.Format = 2 new.ValueFormat = min_inclusive_rec_format new.Coverage = ot.Coverage() new.Coverage.glyphs = glyphs new.ValueCount = num_glyphs new.Value = [None] * num_glyphs for singlePos in lst: if singlePos.Format == 1: val_rec = singlePos.Value for gname in singlePos.Coverage.glyphs: i = glyphs.index(gname) new.Value[i] = copy.deepcopy(val_rec) elif singlePos.Format == 2: for j, gname in enumerate(singlePos.Coverage.glyphs): val_rec = singlePos.Value[j] i = glyphs.index(gname) new.Value[i] = copy.deepcopy(val_rec) return [new]
def build(self): subtables = [] # If multiple glyphs have the same ValueRecord, they can go into # the same subtable which saves space. Therefore, we first build # a reverse mapping from ValueRecord to glyph coverage. values = {} for glyph, valuerecord in self.mapping.items(): values.setdefault(valuerecord, []).append(glyph) # For compliance with the OpenType specification, # we sort the glyph coverage by glyph ID. for glyphs in values.values(): glyphs.sort(key=self.font.getGlyphID) # Make a list of (glyphs, (otBase.ValueRecord, int valueFormat)). # Glyphs with the same otBase.ValueRecord are grouped into one item. values = [(glyphs, makeOpenTypeValueRecord(valrec)) for valrec, glyphs in values.items()] # Find out which glyphs should be encoded as SinglePos format 2. # Format 2 is more compact than format 1 when multiple glyphs # have different values but share the same integer valueFormat. format2 = {} # valueFormat --> [(glyph, value), (glyph, value), ...] for glyphs, (value, valueFormat) in values: if len(glyphs) == 1: glyph = glyphs[0] format2.setdefault(valueFormat, []).append((glyph, value)) # Only use format 2 if multiple glyphs share the same valueFormat. # Otherwise, format 1 is more compact. format2 = [(valueFormat, valueList) for valueFormat, valueList in format2.items() if len(valueList) > 1] format2.sort() format2Glyphs = set() # {"A", "B", "C"} for _, valueList in format2: for (glyph, _) in valueList: format2Glyphs.add(glyph) for valueFormat, valueList in format2: valueList.sort(key=lambda x: self.font.getGlyphID(x[0])) st = otTables.SinglePos() subtables.append(st) st.Format = 2 st.ValueFormat = valueFormat st.Coverage = otTables.Coverage() st.Coverage.glyphs = [glyph for glyph, _value in valueList] st.ValueCount = len(valueList) st.Value = [value for _glyph, value in valueList] # To make the ordering of our subtables deterministic, # we sort subtables by the first glyph ID in their coverage. # Not doing this would be OK for OpenType, but testing the # compiler would be harder with non-deterministic output. values.sort(key=lambda x: self.font.getGlyphID(x[0][0])) for glyphs, (value, valueFormat) in values: if len(glyphs) == 1 and glyphs[0] in format2Glyphs: continue # already emitted as part of a format 2 subtable st = otTables.SinglePos() subtables.append(st) st.Format = 1 st.Coverage = self.buildCoverage_(glyphs) st.Value, st.ValueFormat = value, valueFormat return self.buildLookup_(subtables)