def shapeText(self): features = [] for k, box in self.features.items(): if box.checkState() == Qt.PartiallyChecked: continue features.append({"tag": k, "value": box.isChecked()}) buf = self.buildBuffer() self.messageTable.setRowCount(0) if not self.text: buf.clear_mask() self.qbr.set_buf(buf) self.fullBuffer = buf self.shaperOutput.setText(buf.serialize()) return self.messageTable.clearSelection() self.lastBuffer = None self.skipped = [] self.partialBuffers = {} shaper = Shaper( self.project.fontfeatures, self.project.font, message_function=self.addToTable, ) self.prep_shaper(shaper, buf, features) shaper.execute(buf, features=features) self.qbr.set_buf(buf) self.fullBuffer = buf self.shaperOutput.setText(buf.serialize())
def makeBuffer(self, before_after="before"): buf = VariationAwareBuffer( self.project.font, direction=self.buffer_direction, ) if self.project.variations: buf.location = self.location buf.vf = self.project.variations buf.items = [ VariationAwareBufferItem.new_glyph(g, self.project.font, buf) for g in self.representative_string ] shaper = Shaper(self.project.fontfeatures, self.project.font) shaper.execute(buf, features=self.makeShaperFeatureArray()) routine = Routine(rules=[self.rule]) # print("Before shaping: ", buf.serialize()) if before_after == "after" and self.rule: print("Before application: ", buf.serialize()) print(self.rule.asFea()) buf.clear_mask() # XXX try: routine.apply_to_buffer(buf) except Exception as e: print("Couldn't shape: " + str(e)) print("After application: ", buf.serialize()) return buf
def test_chain(parser): parser.parseString(""" Routine a_to_b { Substitute A -> B; }; Feature liga { Chain X ( A ^a_to_b) Y; }; """) buf = Buffer(parser.font, unicodes="XAYXAX") shaper = Shaper(parser.fontfeatures, parser.font) shaper.execute(buf) assert buf.serialize(position=False) == "X|B|Y|X|A|X"
def test_swap2(parser): parser.parseString(""" LoadPlugin Swap; Feature liga { Swap C ( A B ) E; }; """) buf = Buffer(parser.font, unicodes="XABDCABDCABE") shaper = Shaper(parser.fontfeatures, parser.font) shaper.execute(buf) assert buf.serialize(position=False) == "X|A|B|D|C|A|B|D|C|B|A|E"
def test_swap(parser): parser.parseString(""" LoadPlugin Swap; Feature liga { Swap A B; }; """) buf = Buffer(parser.font, unicodes="CABD") shaper = Shaper(parser.fontfeatures, parser.font) shaper.execute(buf) assert buf.serialize(position=False) == "C|B|A|D"
def test_shaping(request, fontname, hb_args, input_string, expectation): font = TTFont(fontname) ff = unparse(font) bbf = Babelfont.load(fontname) if not bbf: return pytest.skip("Font too busted to use") buf = Buffer(bbf, unicodes=tounicode(input_string)) shaper = Shaper(ff, bbf) feature_string = "" if "[" in hb_args: return pytest.skip("Partial application not supported yet") if "variations" in hb_args: return pytest.skip("Not planning to support variations") if "ttb" in hb_args: return pytest.skip("Not planning to support top-to-bottom") if "rand" in request.node.name: return pytest.skip("Not planning to support rand feature") if "aat" in request.node.name: return pytest.skip("Not planning to support Apple Advanced Typography") if "kern-format2" in request.node.name: return pytest.skip("Not planning to support kern table") if "fraction" in request.node.name: return pytest.skip("Not planning to support automatic fractions") m = re.search(r'--features="([^"]+)"', hb_args) if m: feature_string = m[1] if "--script" in hb_args: m = re.search(r"--script=(\w+)", hb_args) buf.script = script_map[m[1]] shaper.execute(buf, features=feature_string) serialize_options = {} if "--no-glyph-names" in hb_args: serialize_options["names"] = False if "--ned" in hb_args: serialize_options["ned"] = True if "--no-position" in hb_args: serialize_options["position"] = False if "post" not in font or font["post"].formatType != 2.0: serialize_options["names"] = False expectation = re.sub("gid", "", expectation) serialized = buf.serialize(**serialize_options) # Finesse cluster information serialized = re.sub(r"=\d+", "", serialized) expectation = re.sub(r"=\d+", "", expectation) assert "[" + serialized + "]" == expectation
def makeRepresentativeString(self): inputglyphs = [] if not self.rule: return inputglyphs # "x and x[0]" thing because slots may be empty if newly added if hasattr(self.rule, "precontext"): inputglyphs.extend([x and x[0] for x in self.rule.precontext]) inputglyphs.extend([x and x[0] for x in self.rule.shaper_inputs()]) if hasattr(self.rule, "postcontext"): inputglyphs.extend([x and x[0] for x in self.rule.postcontext]) representative_string = [x for x in inputglyphs if x] for ix, g in enumerate(representative_string): if (g.startswith("@") and g[1:] in self.project.fontfeatures.namedClasses.keys()): representative_string[ ix] = self.project.fontfeatures.namedClasses[g[1:]][0] # We use this representative string to guess information about # how the *real* shaping process will take place; buffer direction # and script, and hence choice of complex shaper, and hence from # that choice of features to be processed. unicodes = [ self.project.font.codepointForGlyph(x) for x in representative_string ] unicodes = [x for x in unicodes if x] tounicodes = "".join(map(chr, unicodes)) bufferForGuessing = Buffer(self.project.font, unicodes=tounicodes) self.buffer_direction = bufferForGuessing.direction self.buffer_script = bufferForGuessing.script # print("Guessed buffer direction ", self.buffer_direction) # print("Guessed buffer script ", self.buffer_script) shaper = Shaper(self.project.fontfeatures, self.project.font) bufferForGuessing = Buffer(self.project.font, glyphs=representative_string) shaper.execute(bufferForGuessing) self.availableFeatures = [] for stage in shaper.stages: if not isinstance(stage, list): continue for f in stage: if (f not in self.availableFeatures and f in self.project.fontfeatures.features): self.availableFeatures.append(f) self.makeFeatureButtons() return representative_string
def makeRepresentativeString(self): inputglyphs = [] if not self.rule or not self.rule.bases or not self.rule.marks: return inputglyphs inputglyphs = [ list(self.rule.bases.keys())[0], list(self.rule.marks.keys())[0] ] # We use this representative string to guess information about # how the *real* shaping process will take place; buffer direction # and script, and hence choice of complex shaper, and hence from # that choice of features to be processed. unicodes = [ self.project.font.codepointForGlyph(x) for x in inputglyphs ] unicodes = [x for x in unicodes if x] tounicodes = "".join(map(chr, unicodes)) bufferForGuessing = Buffer(self.project.font, unicodes=tounicodes) self.buffer_direction = bufferForGuessing.direction self.buffer_script = bufferForGuessing.script # print("Guessed buffer direction ", self.buffer_direction) # print("Guessed buffer script ", self.buffer_script) shaper = Shaper(self.project.fontfeatures, self.project.font) shaper.execute(bufferForGuessing) self.availableFeatures = [] for stage in shaper.stages: if not isinstance(stage, list): continue for f in stage: if f not in self.availableFeatures and f in self.project.fontfeatures.features: self.availableFeatures.append(f) self.makeFeatureButtons() return inputglyphs