예제 #1
0
def test_namedclass_in_slot():
    font = Babelfont.load("tests/data/LibertinusSans-Regular.otf")
    buf = Buffer(font, glyphs=["A", "B", "C"])
    r = Routine()
    r.addRule(Substitution([["G", "@AB"]], [["X"]]))
    r.apply_to_buffer(buf, namedclasses={"AB": ["A", "B"]})
    assert buf.serialize(position=False) == "X|X|C"
예제 #2
0
def test_double_application():
    font = Babelfont.load(
        "tests/data/acbe26ce904463c690fb67f70679447059d13ee4.otf")
    buf = Buffer(font, glyphs=["dvKA", "dvVirama", "dvKA", "dvVirama", "dvKA"])
    rule = Substitution([["dvKA"], ["dvVirama"]], [["dvK"]])
    rule.apply_to_buffer(buf)
    assert buf.serialize(position=False) == "dvK|dvK|dvKA"
예제 #3
0
def test_multiple_applications():
    font = Babelfont.load("tests/data/LibertinusSans-Regular.otf")
    buf = Buffer(font, glyphs=["A", "B", "C"])
    r = Routine()
    r.addRule(Substitution([["A"]], [["X"]]))
    r.addRule(Substitution([["B"]], [["Y"]]))
    r.apply_to_buffer(buf)
    assert buf.serialize(position=False) == "X|Y|C"
예제 #4
0
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"
예제 #5
0
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"
예제 #6
0
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"
예제 #7
0
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
예제 #8
0
    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
예제 #9
0
 def would_substitute(self, feature, subbuffer_items):
     """Test whether the feature would apply to a list of BufferItem objects."""
     if not feature in self.plan.fontfeatures.features:
         return False
     subbuffer = Buffer(
         self.buffer.font,
         direction=self.buffer.direction,
         script=self.buffer.script,
         language=self.buffer.language,
     )
     subbuffer.clear_mask()
     subbuffer.items = [copy(x) for x in subbuffer_items]
     subbuffer.clear_mask()
     routines = self.plan.fontfeatures.features[feature]
     for r in routines:
         if isinstance(r, RoutineReference):
             r = r.routine
         for rule in r.rules:
             if rule.stage == "pos":
                 continue
             if any(
                 [
                     rule.would_apply_at_position(subbuffer, i, namedclasses=self.plan.fontfeatures.namedClasses)
                     for i in range(len(subbuffer))
                 ]
             ):
                 return True
     return False
예제 #10
0
 def __init__(self, parent, glyph):
     super().__init__()
     wlayout = QVBoxLayout()
     self.setLayout(wlayout)
     self.parent = parent
     self.glyph = glyph
     buf = Buffer(self.parent.project.font, glyphs=[glyph])
     renderer = QBufferRenderer(self.parent.project, buf)
     wlayout.addWidget(renderer)
     label = QTextEdit(glyph)
     label.setReadOnly(True)
     label.setFrameStyle(QFrame.NoFrame)
     label.setAlignment(Qt.AlignCenter)
     label.setLineWrapMode(QTextEdit.WidgetWidth)
     label.setWordWrapMode(QTextOption.WrapAtWordBoundaryOrAnywhere)
     wlayout.addWidget(label)
     renderer.resizeEvent(None)
     # self.setContentsMargins(QMargins(25, 25, 25, 25))
     self.setMaximumSize(100, 100)
예제 #11
0
    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
예제 #12
0
    def resizeEvent(self, e):
        self.fitInView(self.scene.sceneRect(), Qt.KeepAspectRatio)


if __name__ == "__main__":
    from Flux.project import FluxProject
    from PyQt5.QtWidgets import QApplication, QVBoxLayout
    from fontFeatures.shaperLib.Buffer import Buffer
    import sys

    app = 0
    if QApplication.instance():
        app = QApplication.instance()
    else:
        app = QApplication(sys.argv)

    w = QWidget()
    w.resize(510, 210)
    v_box_1 = QVBoxLayout()

    proj = FluxProject.new("Rajdhani.glyphs")
    buf = Buffer(proj.font, unicodes="ABC")
    buf.map_to_glyphs()
    v_box_1.addWidget(QBufferRenderer(proj, buf))

    w.setLayout(v_box_1)

    w.show()
    sys.exit(app.exec_())