def test_rvrn(latest_otf, otf_font, latest_ttf, ttf_font, wght_val):
    """
    Ensure that the 'rvrn' feature is activated/not activated at expected
    variations. The 'rvrn' feature of this font substitutes a design variation
    of '$' and '¢' at heavier weights.
    """
    test_str = "$2.00 5¢"

    for expected, actual in ((latest_otf, otf_font), (latest_ttf, ttf_font)):
        buf_expected = hb.Buffer()
        buf_expected.add_str(test_str)
        buf_expected.guess_segment_properties()

        buf_actual = hb.Buffer()
        buf_actual.add_str(test_str)
        buf_actual.guess_segment_properties()

        expected.set_variations({"wght": wght_val})
        hb.shape(expected, buf_expected, None)
        infos_expected = buf_expected.glyph_infos

        actual.set_variations({"wght": wght_val})
        hb.shape(actual, buf_actual, None)
        infos_actual = buf_actual.glyph_infos

        assert len(infos_actual) == len(infos_expected)

        for i in range(len(infos_expected)):
            gn_expected = expected.get_glyph_name(infos_expected[i].codepoint)
            gn_actual = actual.get_glyph_name(infos_actual[i].codepoint)

            assert gn_actual == gn_expected
def test_kern_regression(latest_otf, otf_font, latest_ttf, ttf_font, string,
                         use_kerning):

    for expected, actual in ((latest_otf, otf_font), (latest_ttf, ttf_font)):
        features = {"kern": use_kerning}

        buf_expected = hb.Buffer()
        buf_expected.add_str(string)
        buf_expected.guess_segment_properties()

        buf_actual = hb.Buffer()
        buf_actual.add_str(string)
        buf_actual.guess_segment_properties()

        hb.shape(expected, buf_expected, features)
        infos_expected = buf_expected.glyph_infos
        positions_expected = buf_expected.glyph_positions

        hb.shape(actual, buf_actual, features)
        infos_actual = buf_actual.glyph_infos
        positions_actual = buf_actual.glyph_positions

        assert len(infos_expected) == len(infos_actual)

        for i in range(len(infos_expected)):
            gn_expected = expected.get_glyph_name(infos_expected[i].codepoint)
            gn_actual = actual.get_glyph_name(infos_actual[i].codepoint)

            assert gn_actual == gn_expected

            pos_expected = positions_expected[i].x_advance
            pos_actual = positions_actual[i].x_advance

            assert pos_actual == pos_expected
Exemple #3
0
  def pair_kerning(self, left, right):
    """The kerning between two glyphs (specified by name), in font units."""
    if self.face.has_kerning:
      return (self.face.get_kerning(left, right).x >> 6) * self.scale_factor
    else:
      if not self.hbFont:
        with open(self.filename, "rb") as fontfile:
          fontdata = fontfile.read()
        face = hb.Face(fontdata)
        font = hb.Font(face)
        scale = face.upem * self.scale_factor
        font.scale = (scale, scale)
        self.hbFont = font

      buf = hb.Buffer()
      buf.add_str(left+right)
      buf.guess_segment_properties()
      hb.shape(self.hbFont, buf, {"kern":True})
      pos = buf.glyph_positions[0].x_advance
      buf = hb.Buffer()
      buf.add_str(left+right)
      buf.guess_segment_properties()
      hb.shape(self.hbFont, buf, {"kern":False})
      pos2 = buf.glyph_positions[0].x_advance
      return pos-pos2
def test_figs_regression(latest_otf, otf_font, latest_ttf, ttf_font,
                         features_on, result_suffix):
    """Compare figure/digit substitutions against latest release."""
    digit_str = "0123456789"
    features = {feat: True for feat in features_on}

    for expected, actual in ((latest_otf, otf_font), (latest_ttf, ttf_font)):
        buf_expected = hb.Buffer()
        buf_expected.add_str(digit_str)
        buf_expected.guess_segment_properties()

        buf_actual = hb.Buffer()
        buf_actual.add_str(digit_str)
        buf_actual.guess_segment_properties()

        hb.shape(expected, buf_expected, features)
        infos_expected = buf_expected.glyph_infos

        hb.shape(actual, buf_actual, features)
        infos_actual = buf_actual.glyph_infos

        assert len(infos_expected) == len(infos_actual)

        for i in range(len(infos_expected)):
            gn_expected = expected.get_glyph_name(infos_expected[i].codepoint)
            gn_actual = actual.get_glyph_name(infos_actual[i].codepoint)

            assert gn_actual == gn_expected

            cl_expected = infos_expected[i].cluster
            cl_actual = infos_actual[i].cluster

            assert cl_actual == cl_expected
def test_zero_regression(latest_otf, otf_font, latest_ttf, ttf_font):
    zero_str = "90125"
    features = {"zero": True}

    for expected, actual in ((latest_otf, otf_font), (latest_ttf, ttf_font)):
        buf_expected = hb.Buffer()
        buf_expected.add_str(zero_str)
        buf_expected.guess_segment_properties()

        buf_actual = hb.Buffer()
        buf_actual.add_str(zero_str)
        buf_actual.guess_segment_properties()

        hb.shape(expected, buf_expected, features)
        infos_expected = buf_expected.glyph_infos

        hb.shape(actual, buf_actual, features)
        infos_actual = buf_actual.glyph_infos

        assert len(infos_expected) == len(infos_actual)

        for i in range(len(infos_expected)):
            gn_expected = expected.get_glyph_name(infos_expected[i].codepoint)
            gn_actual = actual.get_glyph_name(infos_actual[i].codepoint)

            assert gn_actual == gn_expected

            cl_expected = infos_expected[i].cluster
            cl_actual = infos_actual[i].cluster

            assert cl_actual == cl_expected
Exemple #6
0
    def test_guess_set_segment_properties(self):
        buf = hb.Buffer()
        buf.add_str("הארץ")

        buf.guess_segment_properties()

        assert buf.direction == "rtl"
        assert buf.script == "Hebr"
        # the guessed language seems to be locale specific
        # assert buf.language == "en-us"
        assert buf.language

        buf.direction = "ltr"
        assert buf.direction == "ltr"

        buf.script = "Latn"
        assert buf.script == "Latn"

        buf.language = "he-il"
        assert buf.language == "he-il"

        buf.set_script_from_ot_tag("mym2")
        assert buf.script == "Mymr"

        buf.set_language_from_ot_tag("BGR")
        assert buf.language == "bg"
Exemple #7
0
    def test_message_func(self, blankfont):
        # Glyph IDs 1, 2, 3, 4, 5 map to glyphs a, b, c, d, e.
        # The calt feature replaces c by a in the context e, d, c', b, a.
        # The kern feature kerns b, a by +100.
        string = "edcba"
        buf = hb.Buffer()
        buf.add_str(string)
        buf.guess_segment_properties()

        messages = []
        infos_trace = []
        positions_trace = []

        def message(msg):
            messages.append(msg)
            infos_trace.append(buf.glyph_infos)
            positions_trace.append(buf.glyph_positions)

        buf.set_message_func(message)
        hb.shape(blankfont, buf)
        gids = [g.codepoint for g in buf.glyph_infos]
        assert gids == [5, 4, 1, 2, 1]
        pos = [g.x_advance for g in buf.glyph_positions]
        assert pos == [0, 0, 0, 100, 0]
        # messages: start GSUB lookup, end GSUB lookup, start GPOS lookup, end GPOS lookup
        assert messages == [
            'start lookup 0', 'end lookup 0', 'start lookup 0', 'end lookup 0'
        ]
        gids_trace = [[g.codepoint for g in infos] for infos in infos_trace]
        assert gids_trace == [[5, 4, 3, 2, 1], [5, 4, 1, 2, 1],
                              [5, 4, 1, 2, 1], [5, 4, 1, 2, 1]]
        advances_trace = [[g.x_advance for g in pos]
                          for pos in positions_trace]
        assert advances_trace == [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0],
                                  [0, 0, 0, 0, 0], [0, 0, 0, 100, 0]]
Exemple #8
0
    def shape_text_to_glyph_names(
        self,
        text: str,
        features: dict = None,
        gid_to_name: dict[int, str] = None,
    ) -> list[str]:

        buffer = hb.Buffer()  # type: ignore
        buffer.add_str(text)
        buffer.guess_segment_properties()

        hb.shape(self.font, buffer, features)  # type: ignore

        names = []
        for info, position in zip(buffer.glyph_infos, buffer.glyph_positions):
            gid = info.codepoint
            if gid_to_name is None:
                name = self.font.get_glyph_name(gid)
            else:
                name = gid_to_name.get(gid, f"gid{gid}")
            if name == "space" and position.x_advance == 0:  # HarfBuzz pseudo space for invisible glyphs
                name = "_invisible"
            names.append(name)

        return names
Exemple #9
0
 def test_gid_and_cluster_no_features(self, blankfont, string, expected):
     buf = hb.Buffer()
     buf.add_str(string)
     buf.guess_segment_properties()
     hb.shape(blankfont, buf)
     infos = [(g.codepoint, g.cluster) for g in buf.glyph_infos]
     assert infos == expected
Exemple #10
0
def shaping_string(fontdata, glyphOrder, text, language=None):
    face = hb.Face(fontdata)
    font = hb.Font(face)
    upem = face.upem
    font.scale = (upem, upem)
    hb.ot_font_set_funcs(font)

    buf = hb.Buffer()

    buf.add_str(text)
    buf.guess_segment_properties()
    if language:
        buf.language = language

    features = {"kern": True, "liga": True}
    hb.shape(font, buf, features)

    infos = buf.glyph_infos
    positions = buf.glyph_positions
    outs = []
    for info, pos in zip(buf.glyph_infos, buf.glyph_positions):
        name = glyphOrder[info.codepoint]
        if name in ignorables:
            continue
        outs.append("%s=%i" % (name, info.cluster))
        if pos.position[0] != 0 or pos.position[1] != 0:
            outs[-1] = outs[-1] + "<%i,%i>" % (pos.position[0],
                                               pos.position[1])
    return "|".join(outs)
Exemple #11
0
    def shape(self, text, onchange=None):
        """Shapes a text

    This shapes a piece of text, return a uharfbuzz `Buffer` object.

    Additionally, if an `onchange` function is provided, this will be called
    every time the buffer changes *during* shaping, with the following arguments:

    - ``self``: the vharfbuzz object.
    - ``stage``: either "GSUB" or "GPOS"
    - ``lookupid``: the current lookup ID
    - ``buffer``: a copy of the buffer as a list of lists (glyphname, cluster, position)
    """

        self.prepare_shaper()
        buf = hb.Buffer()
        buf.add_str(text)
        buf.guess_segment_properties()
        self.stage = "GSUB"
        if onchange:
            f = self.make_message_handling_function(buf, onchange)
            buf.set_message_func(f)
        hb.shape(self.hbfont, buf, shapers=self.shapers)
        self.stage = "GPOS"
        return buf
Exemple #12
0
    def test_message_func_return_false(self, blankfont):
        # Glyph IDs 1, 2, 3, 4, 5 map to glyphs a, b, c, d, e.
        # The calt feature replaces c by a in the context e, d, c', b, a.
        # The kern feature kerns b, a by +100.
        string = "edcba"
        buf = hb.Buffer()
        buf.add_str(string)
        buf.guess_segment_properties()

        messages = []
        infos_trace = []
        positions_trace = []

        def message(msg):
            messages.append(msg)
            infos_trace.append(buf.glyph_infos)
            positions_trace.append(buf.glyph_positions)
            return False

        buf.set_message_func(message)
        hb.shape(blankfont, buf)
        gids = [g.codepoint for g in buf.glyph_infos]
        assert gids == [5, 4, 3, 2, 1]
        pos = [g.x_advance for g in buf.glyph_positions]
        assert pos == [0, 0, 0, 0, 0]
        expected_messages = [
            'start table GSUB',
            'start table GPOS',
        ]
        assert messages == expected_messages
        gids_trace = [[g.codepoint for g in infos] for infos in infos_trace]
        assert gids_trace == [[5, 4, 3, 2, 1], [5, 4, 3, 2, 1]]
        advances_trace = [[g.x_advance for g in pos] for pos in positions_trace
                          if pos]
        assert advances_trace == [[0, 0, 0, 0, 0]]
Exemple #13
0
def metrics_from_text( ctx, font_path, text ):
  import uharfbuzz  as HB ### NOTE import after ctx available ###
  mhbfont       = get_mhbfont( ctx, font_path )
  bfr           = HB.Buffer()
  bfr.add_str( text )
  bfr.guess_segment_properties()
  features      = { 'kern': True, 'liga': True, }
  HB.shape( mhbfont.font, bfr, features )
  infos         = bfr.glyph_infos
  positions     = bfr.glyph_positions
  scale         = 1000 / mhbfont.upem
  R             = ctx.AttributeDict()
  width         = 0
  R.width       = width
  R.parts       = []
  for info, position in zip( infos, positions ):
    part                  = ctx.AttributeDict()
    x_advance             = position.x_advance  * scale
    part.dx               = round( x_advance )
    width                += x_advance
    # part.x_offset        = position.x_offset   * scale
    # part.y_advance       = position.y_advance  * scale
    # part.y_offset        = position.y_offset   * scale
    part.fid              = 'f123' ### NOTE fake font ID, to be replaced by viable ID of font ###
    part.gid              = info.codepoint
    R.parts.append( part )
  # ctx.log( '^77767^', part )
  R.width = round( width )
  return R
Exemple #14
0
 def shape_a_text(self, text):
     buf = hb.Buffer()
     buf.add_str(text)
     buf.guess_segment_properties()
     hb.shape(self.hbfont, buf)
     self.direction = buf.direction
     return buf
Exemple #15
0
def draw(surface, paths, text, features):
    bounds = None
    lines = []
    y = 0
    for path in paths:
        font = BlackRendererFont(path)

        buf = hb.Buffer()
        buf.add_str(text)
        buf.guess_segment_properties()
        hb.shape(font.hbFont, buf, features)

        line, rect, height = makeLine(buf, font, y)
        lines.append((font, line, rect, y))

        if bounds is None:
            bounds = rect
        bounds = unionRect(bounds, rect)
        y += height

    with surface.canvas(bounds) as canvas:
        for font, line, rect, y in lines:
            with canvas.savedState():
                # Center align the line.
                x = (bounds[2] - rect[2]) / 2
                canvas.translate(x, y)
                for glyph in line:
                    with canvas.savedState():
                        canvas.translate(glyph.xOffset, glyph.yOffset)
                        font.drawGlyph(glyph.name, canvas)
                    canvas.translate(glyph.xAdvance, glyph.yAdvance)
Exemple #16
0
 def test_message_func_crash(self, blankfont):
     string = "edcba"
     buf = hb.Buffer()
     buf.add_str(string)
     buf.guess_segment_properties()
     message_collector = MessageCollector()
     buf.set_message_func(message_collector.message)
     hb.shape(blankfont, buf)
    def test_features_slice(self, blankfont, string, features, expected):
        buf = hb.Buffer()
        buf.add_str(string)
        buf.guess_segment_properties()
        hb.shape(blankfont, buf, features)

        glyph_names = [blankfont.glyph_to_string(g.codepoint) for g in buf.glyph_infos]
        assert glyph_names == expected
Exemple #18
0
 def shape(self, text, onchange=None):
     self.prepare_shaper()
     buf = hb.Buffer()
     buf.add_str(text)
     buf.guess_segment_properties()
     test = self.make_message_handling_function(buf, onchange)
     if onchange:
         buf.set_message_func(test)
     hb.shape(self.hbfont, buf)
Exemple #19
0
def pair_kerning(font, left, right):
    """The kerning between two glyphs (specified by name), in font units."""
    with open(font, "rb") as fontfile:
        fontdata = fontfile.read()
    face = hb.Face(fontdata)
    font = hb.Font(face)
    scale = face.upem
    font.scale = (scale, scale)
    buf = hb.Buffer()
    buf.add_str(left + right)
    buf.guess_segment_properties()
    hb.shape(font, buf, {"kern": True})
    pos = buf.glyph_positions[0].x_advance
    buf = hb.Buffer()
    buf.add_str(left + right)
    buf.guess_segment_properties()
    hb.shape(font, buf, {"kern": False})
    pos2 = buf.glyph_positions[0].x_advance
    return pos - pos2
 def test_shape_set_shaper(self, blankfont):
     string = "abcde"
     expected = []
     buf = hb.Buffer()
     buf.add_str(string)
     buf.guess_segment_properties()
     hb.shape(blankfont, buf, shapers=["fallback"])
     pos = [g.position for g in buf.glyph_positions]
     expected = [(0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0), (0, 0, 0, 0)]
     assert pos == expected
Exemple #21
0
 def set_text(self, text):
     newtrace = []
     self.clear()
     buf = hb.Buffer()
     buf.add_str(text)
     buf.guess_segment_properties()
     buf.set_message_func(self.process_msg)
     self.stack = [QTreeWidgetItem(["GSUB", ""])]
     self.addTopLevelItem(self.stack[0])
     hb.shape(self.font.vharfbuzz.hbfont, buf)
Exemple #22
0
    def test_cluster_level_int(self):
        buf = hb.Buffer()

        assert buf.cluster_level == 0

        buf.cluster_level = 1
        assert buf.cluster_level == 1

        with pytest.raises(ValueError):
            # 5 is not a valid BufferClusterLevel
            buf.cluster_level = 5
        assert buf.cluster_level == 1
Exemple #23
0
    def shape(self, text, parameters=None, onchange=None):
        """Shapes a text

    This shapes a piece of text.

    Args:
        text (str): A string of text
        parameters: A dictionary containing parameters to pass to Harfbuzz.
            Relevant keys include ``script``, ``direction``, ``language``
            (these three are normally guessed from the string contents),
            ``features``, ``variations`` and ``shaper``.
        onchange: An optional function with three parameters. See below.

    Additionally, if an `onchange` function is provided, this will be called
    every time the buffer changes *during* shaping, with the following arguments:

    - ``self``: the vharfbuzz object.
    - ``stage``: either "GSUB" or "GPOS"
    - ``lookupid``: the current lookup ID
    - ``buffer``: a copy of the buffer as a list of lists (glyphname, cluster, position)

    Returns:
        A uharfbuzz ``hb.Buffer`` object
    """
        if not parameters:
            parameters = {}
        self.prepare_shaper()
        buf = hb.Buffer()
        buf.add_str(text)
        buf.guess_segment_properties()
        if "script" in parameters and parameters["script"]:
            buf.script = parameters["script"]
        if "direction" in parameters and parameters["direction"]:
            buf.direction = parameters["direction"]
        if "language" in parameters and parameters["language"]:
            buf.language = parameters["language"]
        shapers = self.shapers
        if "shaper" in parameters and parameters["shaper"]:
            shapers = [parameters["shaper"]]

        features = parameters.get("features")
        if "variations" in parameters:
            self.hbfont.set_variations(parameters["variations"])
        self.stage = "GSUB"
        if onchange:
            f = self.make_message_handling_function(buf, onchange)
            buf.set_message_func(f)
        hb.shape(self.hbfont, buf, features, shapers=shapers)
        self.stage = "GPOS"
        return buf
def test_basic_var(latest_otf, otf_font, latest_ttf, ttf_font, axis_dict):
    """
    Check x_advances of each character in string at several variations.
    """
    var_str = "Hello, World! 12345 ÀÉÏøÑ [({})]"

    for expected, actual in ((latest_otf, otf_font), (latest_ttf, ttf_font)):
        buf_expected = hb.Buffer()
        buf_expected.add_str(var_str)
        buf_expected.guess_segment_properties()

        buf_actual = hb.Buffer()
        buf_actual.add_str(var_str)
        buf_actual.guess_segment_properties()

        expected.set_variations(axis_dict)
        hb.shape(expected, buf_expected, None)
        infos_expected = buf_expected.glyph_infos
        positions_expected = buf_expected.glyph_positions

        actual.set_variations(axis_dict)
        hb.shape(actual, buf_actual, None)
        infos_actual = buf_actual.glyph_infos
        positions_actual = buf_actual.glyph_positions

        assert len(infos_expected) == len(infos_actual)

        for i in range(len(infos_expected)):
            gn_expected = expected.get_glyph_name(infos_expected[i].codepoint)
            gn_actual = actual.get_glyph_name(infos_actual[i].codepoint)

            assert gn_actual == gn_expected

            pos_expected = positions_expected[i].x_advance
            pos_actual = positions_actual[i].x_advance

            assert pos_actual == pos_expected
 def test_glyh_name_no_features(self, blankfont, string, expected):
     buf = hb.Buffer()
     buf.add_str(string)
     buf.guess_segment_properties()
     hb.shape(blankfont, buf)
     # font.get_glyph_name() returns None if the font does not contain glyph names
     # or if the glyph ID does not exist.
     glyph_names = [blankfont.get_glyph_name(g.codepoint) for g in buf.glyph_infos]
     assert glyph_names == expected
     assert blankfont.get_glyph_name(1000) is None
     # font.glyph_to_string() return "gidN" if the font does not contain glyph names
     # or if the glyph ID does not exist.
     glyph_names = [blankfont.glyph_to_string(g.codepoint) for g in buf.glyph_infos]
     assert glyph_names == expected
     assert blankfont.glyph_to_string(1000) == 'gid1000'
Exemple #26
0
    def test_cluster_level(self):
        buf = hb.Buffer()

        assert buf.cluster_level == hb.BufferClusterLevel.DEFAULT

        buf.cluster_level = hb.BufferClusterLevel.MONOTONE_CHARACTERS
        assert buf.cluster_level == hb.BufferClusterLevel.MONOTONE_CHARACTERS

        buf.cluster_level = hb.BufferClusterLevel.MONOTONE_GRAPHEMES
        assert buf.cluster_level == hb.BufferClusterLevel.MONOTONE_GRAPHEMES

        buf.cluster_level = hb.BufferClusterLevel.CHARACTERS
        assert buf.cluster_level == hb.BufferClusterLevel.CHARACTERS

        buf.cluster_level = hb.BufferClusterLevel.DEFAULT
        assert buf.cluster_level == hb.BufferClusterLevel.DEFAULT
Exemple #27
0
    def test_glyph_h_advance_func(self, blankfont):
        string = "abcde"
        expected = [456, 456, 456, 456, 456]
        buf = hb.Buffer()
        buf.add_str(string)
        buf.guess_segment_properties()

        def h_advance_func(font, gid, data):
            return 456

        funcs = hb.FontFuncs.create()
        funcs.set_glyph_h_advance_func(h_advance_func, None)
        blankfont.funcs = funcs

        hb.shape(blankfont, buf)
        infos = [pos.x_advance for pos in buf.glyph_positions]
        assert infos == expected
Exemple #28
0
    def test_nominal_glyph_func(self, blankfont):
        string = "abcde"
        expected = [97, 98, 99, 100, 101]
        buf = hb.Buffer()
        buf.add_str(string)
        buf.guess_segment_properties()

        def nominal_glyph_func(font, code_point, data):
            return code_point

        funcs = hb.FontFuncs.create()
        funcs.set_nominal_glyph_func(nominal_glyph_func, None)
        blankfont.funcs = funcs

        hb.shape(blankfont, buf)
        infos = [g.codepoint for g in buf.glyph_infos]
        assert infos == expected
Exemple #29
0
 async def shape(self, text):
     if not text:
         return ShapeResult()
     buffer = hb.Buffer()
     buffer.add_str(text)
     font = self.font
     features = self.features_dict
     if font.is_vertical:
         buffer.direction = 'ttb'
         assert features and features['vert']
     else:
         buffer.direction = 'ltr'
         assert not features or not features.get('vert')
     if self.language:
         buffer.language = f'x-hbot{self.language}'
         # buffer.set_language_from_ot_tag(self.language)
     if self.script:
         buffer.script = self.script
         # buffer.set_script_from_ot_tag(self.script)
     logger.debug('%s lang=%s script=%s features=%s',
                  ' '.join(f'U+{ord(ch):04X}' for ch in text),
                  self.language, self.script, features)
     # logger.debug('lang=%s, script=%s, features=%s', buffer.language,
     #              buffer.script, features)
     if utils._log_shaper_logs:
         buffer.set_message_func(
             lambda message: logger.debug('uharfbuzz: %s', message))
     # buffer.cluster_level = hb.BufferClusterLevel.DEFAULT
     # buffer.guess_segment_properties()
     hb.shape(font.hbfont, buffer, features, self._shapers)
     infos = buffer.glyph_infos
     positions = buffer.glyph_positions
     assert len(infos) == len(positions)
     if font.is_vertical:
         glyphs = (GlyphData(info.codepoint, info.cluster, -pos.y_advance,
                             -pos.y_offset)
                   for info, pos in zip(infos, positions))
     else:
         glyphs = (GlyphData(info.codepoint, info.cluster, pos.x_advance,
                             pos.x_offset)
                   for info, pos in zip(infos, positions))
     result = ShapeResult(glyphs)
     self._log_result(result, text)
     return result
Exemple #30
0
def shapeHB(text, font_name, font_size, features: Dict[str, bool] = None):
    font = pdfmetrics.getFont(font_name)
    if not isinstance(font, TTFont):
        # TODO make valid for all types of fonts
        raise RLKerningError("Not a TTF font")

    fontdata = font.face._ttf_data
    face = hb.Face(fontdata)
    font = hb.Font(face)

    # HB scales to integers in offset and advance so very big scale
    # will divide by SCALE_MULT to get the actual size in fractional points
    font.scale = (font_size * SCALE_MULT, font_size * SCALE_MULT)
    hb.ot_font_set_funcs(font)
    buf = hb.Buffer()
    buf.add_str(text)
    buf.guess_segment_properties()
    hb.shape(font, buf, features)

    return buf