def test_complex(self): pos1 = Substitution(["a"], ["b"]) pos2 = Substitution(["b"], ["c"]) r1 = Routine(rules=[pos1], name="dummy1") r2 = Routine(rules=[pos2], name="dummy2") rr1 = RoutineReference(routine=r1) rr2 = RoutineReference(routine=r2) c = Chaining([["a"], ["b"]], lookups=[[rr1, rr2], None]) self.assertEqual(c.asFea(), "sub a' lookup dummy1 lookup dummy2 b';")
def fromXML(klass, el): """Creates a FontFeatures object from a lxml Element object.""" f = klass() from fontFeatures import RoutineReference, Routine for part in el: if part.tag == "namedclasses": for cl_el in part: f.namedClasses[cl_el.get("name")] = [g.text for g in cl_el] elif part.tag == "routines": f.routines = [Routine.fromXML(r) for r in part] elif part.tag == "features": for feat in part: f.features[feat.get("name")] = [ RoutineReference.fromXML(x) for x in feat ] elif part.tag == "anchors": for glyph in part: f.anchors[glyph.get("name")] = { el.get("name"): (int(el.get("x")), int(el.get("y"))) for el in glyph } elif part.tag == "glyphclasses": for cl_el in part: f.glyphclasses[cl_el.get("name")] = cl_el.get("class") for refs in f.features.values(): for ref in refs: ref.resolve(f) return f
def test_simple_sub(self): pos = Substitution(["a"], ["b"]) r = Routine(rules=[pos], name="dummy") rr = RoutineReference(routine=r) c = Chaining([["a"], ["b"]], lookups=[[rr], None]) self.assertEqual(c.asFea(), "sub a' lookup dummy b';")
def chainingLookupChanged(self): l = self.sender() if l.currentIndex() == 0: self.rule.lookups[l.ix] = [] else: self.rule.lookups[l.ix] = [RoutineReference(name=l.currentText())] self.setComboboxWarningIfNeeded(l) self.resetBuffer()
def test_complex_pos(self): v = ValueRecord(xAdvance=120) pos1 = Positioning(["a"], [v]) r1 = Routine(rules=[pos1]) rr1 = RoutineReference(routine=r1) c = Chaining([["a"], ["b"]], lookups=[[rr1], None]) c.feaPreamble(FontFeatures()) self.assertEqual(c.asFea(), "pos a' lookup ChainedRoutine1 b';")
def test_simple_pos(self): v = ValueRecord(xAdvance=120) pos = Positioning(["a"], [v]) r = Routine(rules=[pos], name="dummy") rr = RoutineReference(routine=r) c = Chaining([["a"], ["b"]], lookups=[[rr], None]) self.assertEqual(c.asFea(), "pos a' lookup dummy b';") self.assertEqual( etree.tostring(c.toXML()), '<chaining><lookups><slot><routinereference name="dummy"/></slot><slot><lookup/></slot></lookups><input><slot><glyph>a</glyph></slot><slot><glyph>b</glyph></slot></input></chaining>' .encode("utf-8"))
def _collectStatements(self, doc): # Collect and sort group definitions first, to make sure a group # definition that references other groups comes after them since VOLT # does not enforce such ordering, and feature file require it. groups = [ s for s in doc.statements if isinstance(s, VAst.GroupDefinition) ] for statement in sorted(groups, key=lambda x: Group(x)): self._groupDefinition(statement) for statement in doc.statements: if isinstance(statement, VAst.GlyphDefinition): self._glyphDefinition(statement) elif isinstance(statement, VAst.AnchorDefinition): self._anchorDefinition(statement) elif isinstance(statement, VAst.SettingDefinition): self._settingDefinition(statement) elif isinstance(statement, VAst.GroupDefinition): pass # Handled above elif isinstance(statement, VAst.ScriptDefinition): self._scriptDefinition(statement) elif not isinstance(statement, VAst.LookupDefinition): raise NotImplementedError(statement) # Lookup definitions need to be handled last as they reference glyph # and mark classes that might be defined after them. for statement in doc.statements: if isinstance(statement, VAst.LookupDefinition): self._lookupDefinition(statement) # Now rearrange features for feature, thing in self._features.items(): for script, thing in thing.items(): for lang, lookups in thing.items(): for lookup in lookups: ref = RoutineReference(name=lookup) ref.resolve(self.ff) ref.language = (script, lang) self.ff.addFeature(feature, [ref])
def test_routine_partition(): f = FontFeatures() s1 = Substitution([["A"]], [["A.grk"]], languages=["grek/*"]) s2 = Substitution([["A"]], [["A.esp"]], languages=["latn/ESP "]) r = Routine(rules=[s1, s2], flags=0x2) f.routines.append(r) dummy = Routine(rules=[Substitution([["G"]], [["G"]])]) f.routines.append(dummy) c = Chaining( [["A"], ["V"]], lookups=[ [RoutineReference(routine=dummy), RoutineReference(routine=r)], [RoutineReference(routine=r), RoutineReference(routine=dummy)], ]) r2 = Routine(rules=[c]) f.routines.append(r2) f.addFeature("locl", [r]) f.partitionRoutine(r, lambda rule: tuple(rule.languages or [])) assert len(f.routines) == 4 assert f.routines[0].flags == f.routines[1].flags assert len(f.routines[0].rules) == 1 assert len(f.routines[1].rules) == 1 assert f.routines[0].rules[0].replacement[0][0] == "A.grk" assert f.routines[1].rules[0].replacement[0][0] == "A.esp" assert len(c.lookups[0]) == 3 assert len(f.features["locl"]) == 2
def fromXML(klass, el): from fontFeatures import Routine, RoutineReference rule = klass(klass._slotArray(klass, el.find("input")), precontext=klass._slotArray(klass, el.find("precontext")), postcontext=klass._slotArray(klass, el.find("postcontext")), address=el.get("address"), languages=el.get("languages"), flags=int(el.get("flags") or 0)) lookupsxml = el.find("lookups") rule.lookups = [] for slot in lookupsxml: routines = [] for lu in slot: if lu.tag == "routinereference": routines.append(RoutineReference.fromXML(lu)) elif lu.tag == "routine": routines.append(Routine.fromXML(lu)) rule.lookups.append(routines) return rule