Skip to content

Commit 1000934

Browse files
committed
Bind hb_buffer_serialize()
1 parent 99ef1a7 commit 1000934

3 files changed

Lines changed: 140 additions & 0 deletions

File tree

src/uharfbuzz/_harfbuzz.pyx

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,21 @@ class BufferContentType(IntEnum):
142142
UNICODE = HB_BUFFER_CONTENT_TYPE_UNICODE
143143
GLYPHS = HB_BUFFER_CONTENT_TYPE_GLYPHS
144144

145+
class BufferSerializeFormat(IntEnum):
146+
TEXT = HB_BUFFER_SERIALIZE_FORMAT_TEXT
147+
JSON = HB_BUFFER_SERIALIZE_FORMAT_JSON
148+
INVALID = HB_BUFFER_SERIALIZE_FORMAT_INVALID
149+
150+
class BufferSerializeFlags(IntFlag):
151+
DEFAULT = HB_BUFFER_SERIALIZE_FLAG_DEFAULT
152+
NO_CLUSTERS = HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS
153+
NO_POSITIONS = HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS
154+
NO_GLYPH_NAMES = HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES
155+
GLYPH_EXTENTS = HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS
156+
GLYPH_FLAGS = HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS
157+
NO_ADVANCES = HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES
158+
DEFINED = HB_BUFFER_SERIALIZE_FLAG_DEFINED
159+
145160
cdef class Buffer:
146161
cdef hb_buffer_t* _hb_buffer
147162
cdef object _message_callback
@@ -371,6 +386,34 @@ cdef class Buffer:
371386
self._message_callback = callback
372387
hb_buffer_set_message_func(self._hb_buffer, msgcallback, <void*>callback, NULL)
373388

389+
def serialize(self,
390+
font: Font,
391+
format: BufferSerializeFormat = BufferSerializeFormat.TEXT,
392+
flags: BufferSerializeFlags = BufferSerializeFlags.DEFAULT) -> str:
393+
cdef unsigned int num_glyphs = hb_buffer_get_length(self._hb_buffer)
394+
cdef unsigned int start = 0
395+
cdef char cstr[STATIC_ARRAY_SIZE]
396+
cdef unsigned int consumed
397+
cdef bytes packed = b""
398+
399+
while start < num_glyphs:
400+
start += hb_buffer_serialize(
401+
self._hb_buffer,
402+
start,
403+
num_glyphs,
404+
cstr,
405+
STATIC_ARRAY_SIZE,
406+
&consumed,
407+
font._hb_font,
408+
format,
409+
flags
410+
)
411+
if consumed == 0:
412+
break
413+
packed += cstr[:consumed]
414+
415+
return packed.decode()
416+
374417

375418
cdef class Blob:
376419
cdef hb_blob_t* _hb_blob

src/uharfbuzz/charfbuzz.pxd

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,21 @@ cdef extern from "hb.h":
155155

156156
HB_BUFFER_FLAG_DEFINED
157157

158+
ctypedef enum hb_buffer_serialize_format_t:
159+
HB_BUFFER_SERIALIZE_FORMAT_TEXT
160+
HB_BUFFER_SERIALIZE_FORMAT_JSON
161+
HB_BUFFER_SERIALIZE_FORMAT_INVALID
162+
163+
ctypedef enum hb_buffer_serialize_flags_t:
164+
HB_BUFFER_SERIALIZE_FLAG_DEFAULT
165+
HB_BUFFER_SERIALIZE_FLAG_NO_CLUSTERS
166+
HB_BUFFER_SERIALIZE_FLAG_NO_POSITIONS
167+
HB_BUFFER_SERIALIZE_FLAG_NO_GLYPH_NAMES
168+
HB_BUFFER_SERIALIZE_FLAG_GLYPH_EXTENTS
169+
HB_BUFFER_SERIALIZE_FLAG_GLYPH_FLAGS
170+
HB_BUFFER_SERIALIZE_FLAG_NO_ADVANCES
171+
HB_BUFFER_SERIALIZE_FLAG_DEFINED
172+
158173
hb_buffer_t* hb_buffer_create()
159174
hb_bool_t hb_buffer_allocation_successful(hb_buffer_t* buffer)
160175
void hb_buffer_reset(hb_buffer_t *buffer)
@@ -215,6 +230,15 @@ cdef extern from "hb.h":
215230
hb_codepoint_t hb_buffer_get_invisible_glyph(const hb_buffer_t *buffer)
216231
void hb_buffer_set_not_found_glyph(hb_buffer_t *buffer, hb_codepoint_t not_found)
217232
hb_codepoint_t hb_buffer_get_not_found_glyph(const hb_buffer_t *buffer)
233+
unsigned int hb_buffer_serialize(hb_buffer_t *buffer,
234+
unsigned int start,
235+
unsigned int end,
236+
char *buf,
237+
unsigned int buf_size,
238+
unsigned int *buf_consumed,
239+
hb_font_t *font,
240+
hb_buffer_serialize_format_t format,
241+
hb_buffer_serialize_flags_t flags)
218242

219243

220244
# hb-face.h

tests/test_uharfbuzz.py

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,79 @@ def test_properties(self):
220220
buf.reset()
221221
assert buf.flags == hb.BufferFlags.DEFAULT
222222

223+
@pytest.mark.parametrize(
224+
"glyphs,format,flags,expected",
225+
[
226+
(
227+
False,
228+
hb.BufferSerializeFormat.TEXT,
229+
hb.BufferSerializeFlags.DEFAULT,
230+
"<U+0061=0|U+0062=1|U+0063=2|U+0064=3|U+0065=4>",
231+
),
232+
(
233+
False,
234+
hb.BufferSerializeFormat.TEXT,
235+
hb.BufferSerializeFlags.NO_CLUSTERS,
236+
"<U+0061|U+0062|U+0063|U+0064|U+0065>",
237+
),
238+
(
239+
True,
240+
hb.BufferSerializeFormat.TEXT,
241+
hb.BufferSerializeFlags.DEFAULT,
242+
"[a=0+0|b=1+0|c=2+0|d=3+0|e=4+0]",
243+
),
244+
(
245+
True,
246+
hb.BufferSerializeFormat.TEXT,
247+
hb.BufferSerializeFlags.DEFAULT
248+
| hb.BufferSerializeFlags.NO_CLUSTERS
249+
| hb.BufferSerializeFlags.NO_POSITIONS,
250+
"[a|b|c|d|e]",
251+
),
252+
(
253+
False,
254+
hb.BufferSerializeFormat.JSON,
255+
hb.BufferSerializeFlags.DEFAULT,
256+
'[{"u":97,"cl":0},{"u":98,"cl":1},{"u":99,"cl":2},'
257+
'{"u":100,"cl":3},{"u":101,"cl":4}]',
258+
),
259+
(
260+
False,
261+
hb.BufferSerializeFormat.JSON,
262+
hb.BufferSerializeFlags.NO_CLUSTERS,
263+
'[{"u":97},{"u":98},{"u":99},{"u":100},{"u":101}]',
264+
),
265+
(
266+
True,
267+
hb.BufferSerializeFormat.JSON,
268+
hb.BufferSerializeFlags.DEFAULT,
269+
'[{"g":"a","cl":0,"dx":0,"dy":0,"ax":0,"ay":0},'
270+
'{"g":"b","cl":1,"dx":0,"dy":0,"ax":0,"ay":0},'
271+
'{"g":"c","cl":2,"dx":0,"dy":0,"ax":0,"ay":0},'
272+
'{"g":"d","cl":3,"dx":0,"dy":0,"ax":0,"ay":0},'
273+
'{"g":"e","cl":4,"dx":0,"dy":0,"ax":0,"ay":0}]',
274+
),
275+
(
276+
True,
277+
hb.BufferSerializeFormat.JSON,
278+
hb.BufferSerializeFlags.DEFAULT
279+
| hb.BufferSerializeFlags.NO_CLUSTERS
280+
| hb.BufferSerializeFlags.NO_POSITIONS,
281+
'[{"g":"a"},{"g":"b"},{"g":"c"},{"g":"d"},{"g":"e"}]',
282+
),
283+
],
284+
)
285+
def test_serialize(self, glyphs, format, flags, expected):
286+
font = hb.Font(hb.Face(ADOBE_BLANK_TTF_PATH.read_bytes()))
287+
288+
buf = hb.Buffer()
289+
buf.add_str("abcde")
290+
buf.guess_segment_properties()
291+
if glyphs:
292+
hb.shape(font, buf)
293+
294+
assert buf.serialize(font, format=format, flags=flags) == expected
295+
223296

224297
class TestBlob:
225298
def test_from_file_path_fail(self):

0 commit comments

Comments
 (0)