From 5d0e66b01696c59422b41090c5b23fb94606e56f Mon Sep 17 00:00:00 2001 From: Khaled Hosny Date: Sun, 1 Aug 2021 21:28:49 +0200 Subject: [PATCH 1/4] Add basic Blob class --- .gitignore | 1 + setup.py | 3 +++ src/uharfbuzz/_harfbuzz.pyx | 26 ++++++++++++++++++++++++++ src/uharfbuzz/charfbuzz.pxd | 9 +++++++++ 4 files changed, 39 insertions(+) diff --git a/.gitignore b/.gitignore index 58a848b..562d3ee 100644 --- a/.gitignore +++ b/.gitignore @@ -13,6 +13,7 @@ MANIFEST build dist _skbuild/ +venv/ # Unit test / coverage files .tox/* diff --git a/setup.py b/setup.py index f0b1f1c..125402c 100755 --- a/setup.py +++ b/setup.py @@ -24,6 +24,9 @@ libraries = [] if platform.system() != 'Windows': extra_compile_args.append('-std=c++11') + define_macros.append(('HAVE_MMAP', '1')) + define_macros.append(('HAVE_UNISTD_H', '1')) + define_macros.append(('HAVE_SYS_MMAN_H', '1')) else: define_macros.append(('HAVE_DIRECTWRITE', '1')) #define_macros.append(('HAVE_UNISCRIBE', '1')) diff --git a/src/uharfbuzz/_harfbuzz.pyx b/src/uharfbuzz/_harfbuzz.pyx index 04d7827..d843cfc 100644 --- a/src/uharfbuzz/_harfbuzz.pyx +++ b/src/uharfbuzz/_harfbuzz.pyx @@ -5,6 +5,7 @@ from libc.stdlib cimport free, malloc from libc.string cimport const_char from collections import namedtuple from typing import Callable, Dict, List, Sequence, Tuple, Union +from pathlib import Path cdef extern from "Python.h": @@ -276,6 +277,31 @@ cdef class Buffer: hb_buffer_set_message_func(self._hb_buffer, msgcallback, callback, NULL) +cdef class Blob: + cdef hb_blob_t* _hb_blob + cdef object _data + + def __cinit__(self, bytes data): + if data is not None: + self._data = data + self._hb_blob = hb_blob_create( + data, len(data), HB_MEMORY_MODE_READONLY, NULL, NULL) + else: + self._hb_blob = NULL + + @classmethod + def from_file_path(cls, filename: Union[str, Path]): + cdef bytes packed = str(filename).encode() + cdef Blob inst = cls(None) + inst._hb_blob = hb_blob_create_from_file(packed) + return inst + + def __dealloc__(self): + if self._hb_blob is not NULL: + hb_blob_destroy(self._hb_blob) + self._data = None + + cdef hb_user_data_key_t k diff --git a/src/uharfbuzz/charfbuzz.pxd b/src/uharfbuzz/charfbuzz.pxd index d87b599..c67ac62 100644 --- a/src/uharfbuzz/charfbuzz.pxd +++ b/src/uharfbuzz/charfbuzz.pxd @@ -73,8 +73,17 @@ cdef extern from "hb.h": hb_memory_mode_t mode, void* user_data, hb_destroy_func_t destroy) + hb_blob_t* hb_blob_create_from_file( + const char *file_name) + void hb_blob_destroy(hb_blob_t* blob) + const char* hb_blob_get_data( + hb_blob_t *blob, unsigned int *length) + + unsigned int hb_blob_get_length( + hb_blob_t *blob) + # hb-buffer.h ctypedef struct hb_buffer_t: pass From 12a40a33ecfe92202037c32c39d6e827cdaf010f Mon Sep 17 00:00:00 2001 From: Khaled Hosny Date: Sun, 1 Aug 2021 22:23:33 +0200 Subject: [PATCH 2/4] Use Blob to create Face Fixes https://github.com/harfbuzz/uharfbuzz/issues/52 --- README.md | 7 +++---- src/uharfbuzz/_harfbuzz.pyx | 16 ++++++++-------- tests/test_uharfbuzz.py | 6 ++++-- 3 files changed, 15 insertions(+), 14 deletions(-) diff --git a/README.md b/README.md index 61c4721..f5d697d 100644 --- a/README.md +++ b/README.md @@ -14,12 +14,11 @@ import sys import uharfbuzz as hb -with open(sys.argv[1], 'rb') as fontfile: - fontdata = fontfile.read() - +fontfile = sys.argv[1] text = sys.argv[2] -face = hb.Face(fontdata) +blob = hb.Blob.from_file_path(fontfile) +face = hb.Face(blob) font = hb.Font(face) buf = hb.Buffer() diff --git a/src/uharfbuzz/_harfbuzz.pyx b/src/uharfbuzz/_harfbuzz.pyx index d843cfc..be5fb99 100644 --- a/src/uharfbuzz/_harfbuzz.pyx +++ b/src/uharfbuzz/_harfbuzz.pyx @@ -325,22 +325,22 @@ cdef hb_blob_t* _reference_table_func( cdef class Face: cdef hb_face_t* _hb_face cdef object _reference_table_func - cdef object _blob + cdef Blob _blob - def __cinit__(self, bytes blob, int index=0): - cdef hb_blob_t* hb_blob + def __cinit__(self, blob: Union[Blob, bytes], int index=0): if blob is not None: - self._blob = blob - hb_blob = hb_blob_create( - blob, len(blob), HB_MEMORY_MODE_READONLY, NULL, NULL) - self._hb_face = hb_face_create(hb_blob, index) - hb_blob_destroy(hb_blob) + if not isinstance(blob, Blob): + self._blob = Blob(blob) + else: + self._blob = blob + self._hb_face = hb_face_create(self._blob._hb_blob, index) else: self._hb_face = NULL def __dealloc__(self): if self._hb_face is not NULL: hb_face_destroy(self._hb_face) + self._blob = None # DEPRECATED: use the normal constructor @classmethod diff --git a/tests/test_uharfbuzz.py b/tests/test_uharfbuzz.py index 5d9ebdd..bf7c88e 100644 --- a/tests/test_uharfbuzz.py +++ b/tests/test_uharfbuzz.py @@ -26,7 +26,8 @@ def blankfont(): {gid=8, name="u1F4A9", code=0x1F4A9}, # PILE OF POO ] """ - face = hb.Face(ADOBE_BLANK_TTF_PATH.read_bytes()) + blob = hb.Blob.from_file_path(ADOBE_BLANK_TTF_PATH) + face = hb.Face(blob) font = hb.Font(face) return font @@ -39,7 +40,8 @@ def opensans(): {gid=1, name="A", code=0x41}, ] """ - face = hb.Face(OPEN_SANS_TTF_PATH.read_bytes()) + blob = hb.Blob(OPEN_SANS_TTF_PATH.read_bytes()) + face = hb.Face(blob) font = hb.Font(face) return font From f054f3236baf3a068993c94a2b41a8104602b6ef Mon Sep 17 00:00:00 2001 From: Khaled Hosny Date: Mon, 2 Aug 2021 00:39:26 +0200 Subject: [PATCH 3/4] Less NULL checks HarfBuzz's _create() functions don't return NULL but empty objects on failure, and in cases we were assigning to NULL ourselves, use the corresponding _get_empty() functions instead. --- src/uharfbuzz/_harfbuzz.pyx | 22 ++++++++-------------- src/uharfbuzz/charfbuzz.pxd | 4 ++++ 2 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/uharfbuzz/_harfbuzz.pyx b/src/uharfbuzz/_harfbuzz.pyx index be5fb99..8862d28 100644 --- a/src/uharfbuzz/_harfbuzz.pyx +++ b/src/uharfbuzz/_harfbuzz.pyx @@ -103,8 +103,7 @@ cdef class Buffer: self._message_callback = None def __dealloc__(self): - if self._hb_buffer is not NULL: - hb_buffer_destroy(self._hb_buffer) + hb_buffer_destroy(self._hb_buffer) # DEPRECATED: use the normal constructor @classmethod @@ -287,7 +286,7 @@ cdef class Blob: self._hb_blob = hb_blob_create( data, len(data), HB_MEMORY_MODE_READONLY, NULL, NULL) else: - self._hb_blob = NULL + self._hb_blob = hb_blob_get_empty() @classmethod def from_file_path(cls, filename: Union[str, Path]): @@ -297,8 +296,7 @@ cdef class Blob: return inst def __dealloc__(self): - if self._hb_blob is not NULL: - hb_blob_destroy(self._hb_blob) + hb_blob_destroy(self._hb_blob) self._data = None @@ -335,11 +333,10 @@ cdef class Face: self._blob = blob self._hb_face = hb_face_create(self._blob._hb_blob, index) else: - self._hb_face = NULL + self._hb_face = hb_face_get_empty() def __dealloc__(self): - if self._hb_face is not NULL: - hb_face_destroy(self._hb_face) + hb_face_destroy(self._hb_face) self._blob = None # DEPRECATED: use the normal constructor @@ -389,8 +386,7 @@ cdef class Font: self._face = face def __dealloc__(self): - if self._hb_font is not NULL: - hb_font_destroy(self._hb_font) + hb_font_destroy(self._hb_font) self._face = self._ffuncs = None # DEPRECATED: use the normal constructor @@ -587,8 +583,7 @@ cdef class FontFuncs: self._hb_ffuncs = hb_font_funcs_create() def __dealloc__(self): - if self._hb_ffuncs is not NULL: - hb_font_funcs_destroy(self._hb_ffuncs) + hb_font_funcs_destroy(self._hb_ffuncs) # DEPRECATED: use the normal constructor @classmethod @@ -868,8 +863,7 @@ cdef class DrawFuncs: self._user_data = None def __dealloc__(self): - if self._hb_drawfuncs is not NULL: - hb_draw_funcs_destroy(self._hb_drawfuncs) + hb_draw_funcs_destroy(self._hb_drawfuncs) def draw_glyph(self, font: Font, gid: int, user_data: object): self._user_data = user_data diff --git a/src/uharfbuzz/charfbuzz.pxd b/src/uharfbuzz/charfbuzz.pxd index c67ac62..7361c7d 100644 --- a/src/uharfbuzz/charfbuzz.pxd +++ b/src/uharfbuzz/charfbuzz.pxd @@ -84,6 +84,8 @@ cdef extern from "hb.h": unsigned int hb_blob_get_length( hb_blob_t *blob) + hb_blob_t* hb_blob_get_empty() + # hb-buffer.h ctypedef struct hb_buffer_t: pass @@ -173,6 +175,8 @@ cdef extern from "hb.h": hb_bool_t replace) void hb_face_destroy(hb_face_t* face) + hb_face_t* hb_face_get_empty() + # hb-font.h ctypedef struct hb_font_funcs_t: pass From 84d942955bab8ebd7eca6b274044550832aa865a Mon Sep 17 00:00:00 2001 From: Khaled Hosny Date: Mon, 2 Aug 2021 09:33:11 +0200 Subject: [PATCH 4/4] Use os.fsencode() to encode file paths --- src/uharfbuzz/_harfbuzz.pyx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/uharfbuzz/_harfbuzz.pyx b/src/uharfbuzz/_harfbuzz.pyx index 8862d28..866ce8e 100644 --- a/src/uharfbuzz/_harfbuzz.pyx +++ b/src/uharfbuzz/_harfbuzz.pyx @@ -1,4 +1,5 @@ #cython: language_level=3 +import os from enum import IntEnum from .charfbuzz cimport * from libc.stdlib cimport free, malloc @@ -290,7 +291,7 @@ cdef class Blob: @classmethod def from_file_path(cls, filename: Union[str, Path]): - cdef bytes packed = str(filename).encode() + cdef bytes packed = os.fsencode(filename) cdef Blob inst = cls(None) inst._hb_blob = hb_blob_create_from_file(packed) return inst