def asFeaAST(self): b = feaast.Block() if self.is_cursive: allglyphs = set(self.bases.keys()) | set(self.marks.keys()) for g in allglyphs: b.statements.append( feaast.CursivePosStatement( glyphref([g]), g in self.bases and feaast.Anchor(*self.bases[g]), g in self.marks and feaast.Anchor(*self.marks[g]), )) else: if not hasattr(self, "baseslist"): sortByAnchor(self) # e.g. when testing for base in self.baseslist: statementtype = feaast.MarkBasePosStatement if self.font: if categorize_glyph(self.font, base[0][0])[0] == "mark": statementtype = feaast.MarkMarkPosStatement b.statements.append( statementtype( glyphref(base[0]), [[ feaast.Anchor(*base[1]), feaast.MarkClass(self.base_name) ]], )) return b
def parse_position_cursive_(self, enumerated, vertical): location = self.cur_token_location_ self.expect_keyword_("cursive") if enumerated: raise FeatureLibError( '"enumerate" is not allowed with ' 'cursive attachment positioning', location) glyphclass = self.parse_glyphclass_(accept_glyphname=True).glyphSet() entryAnchor = self.parse_anchor_() exitAnchor = self.parse_anchor_() self.expect_symbol_(";") return ast.CursivePosStatement(location, glyphclass, entryAnchor, exitAnchor)
def asFeaAST(self): b = feaast.Block() # if any( # isinstance(x[0], VariableScalar) or isinstance(x[1], VariableScalar) # for x in list(self.bases.values()) + list(self.marks.values()) # ): # raise ValueError("Can't directly express a variable anchor in FEA") if self.is_cursive: allglyphs = set(self.bases.keys()) | set(self.marks.keys()) for g in allglyphs: b.statements.append( feaast.CursivePosStatement( _glyphref([g]), g in self.bases and feaast.Anchor(*self.bases[g]), g in self.marks and feaast.Anchor(*self.marks[g]), )) else: if not hasattr(self, "baseslist"): sortByAnchor(self) # e.g. when testing for base in self.baseslist: statementtype = feaast.MarkBasePosStatement if self.font: if categorize_glyph(self.font, base[0][0])[0] == "mark": statementtype = feaast.MarkMarkPosStatement if self.force_markmark: statementtype = feaast.MarkMarkPosStatement b.statements.append( statementtype( _glyphref(base[0]), [[ feaast.Anchor(*base[1]), feaast.MarkClass(self.base_name) ]], )) return b
def _gposLookup(self, lookup, fealookup): statements = fealookup.statements pos = lookup.pos if isinstance(pos, VAst.PositionAdjustPairDefinition): for (idx1, idx2), (pos1, pos2) in pos.adjust_pair.items(): coverage_1 = pos.coverages_1[idx1 - 1] coverage_2 = pos.coverages_2[idx2 - 1] # If not both are groups, use “enum pos” otherwise makeotf will # fail. enumerated = False for item in coverage_1 + coverage_2: if not isinstance(item, VAst.GroupName): enumerated = True glyphs1 = self._coverage(coverage_1) glyphs2 = self._coverage(coverage_2) record1 = self._adjustment(pos1) record2 = self._adjustment(pos2) assert len(glyphs1) == 1 assert len(glyphs2) == 1 statements.append( ast.PairPosStatement(glyphs1[0], record1, glyphs2[0], record2, enumerated=enumerated)) elif isinstance(pos, VAst.PositionAdjustSingleDefinition): for a, b in pos.adjust_single: glyphs = self._coverage(a) record = self._adjustment(b) assert len(glyphs) == 1 statements.append( ast.SinglePosStatement([(glyphs[0], record)], [], [], False)) elif isinstance(pos, VAst.PositionAttachDefinition): anchors = {} for marks, classname in pos.coverage_to: for mark in marks: # Set actually used mark classes. Basically a hack to get # around the feature file syntax limitation of making mark # classes global and not allowing mark positioning to # specify mark coverage. for name in mark.glyphSet(): key = (name, "MARK_" + classname) self._markclasses[key].used = True markclass = ast.MarkClass(self._className(classname)) for base in pos.coverage: for name in base.glyphSet(): if name not in anchors: anchors[name] = [] if classname not in anchors[name]: anchors[name].append(classname) for name in anchors: components = 1 if name in self._ligatures: components = self._ligatures[name] marks = [] for mark in anchors[name]: markclass = ast.MarkClass(self._className(mark)) for component in range(1, components + 1): if len(marks) < component: marks.append([]) anchor = None if component in self._anchors[name][mark]: anchor = self._anchors[name][mark][component] marks[component - 1].append((anchor, markclass)) base = self._glyphName(name) if name in self._marks: mark = ast.MarkMarkPosStatement(base, marks[0]) elif name in self._ligatures: mark = ast.MarkLigPosStatement(base, marks) else: mark = ast.MarkBasePosStatement(base, marks[0]) statements.append(mark) elif isinstance(pos, VAst.PositionAttachCursiveDefinition): # Collect enter and exit glyphs enter_coverage = [] for coverage in pos.coverages_enter: for base in coverage: for name in base.glyphSet(): enter_coverage.append(name) exit_coverage = [] for coverage in pos.coverages_exit: for base in coverage: for name in base.glyphSet(): exit_coverage.append(name) # Write enter anchors, also check if the glyph has exit anchor and # write it, too. for name in enter_coverage: glyph = self._glyphName(name) entry = self._anchors[name]["entry"][1] exit = None if name in exit_coverage: exit = self._anchors[name]["exit"][1] exit_coverage.pop(exit_coverage.index(name)) statements.append(ast.CursivePosStatement(glyph, entry, exit)) # Write any remaining exit anchors. for name in exit_coverage: glyph = self._glyphName(name) exit = self._anchors[name]["exit"][1] statements.append(ast.CursivePosStatement(glyph, None, exit)) else: raise NotImplementedError(pos)