1cdef extern from "stdlib.h":
2    ctypedef int size_t
3    void *malloc(size_t size)
4    void free(void* ptr)
5
6cdef extern from "ft2build.h" :
7    pass
8
9cdef extern from "freetype/freetype.h" :
10    ctypedef void *FT_Library
11    ctypedef void *FT_Face
12    ctypedef int FT_Error
13
14    FT_Error FT_Init_FreeType (FT_Library *alib)
15    FT_Error FT_Done_FreeType (FT_Library alib)
16    FT_Error FT_Done_Face (FT_Face alib)
17    FT_Error FT_New_Face( FT_Library library, char *path, unsigned long index, FT_Face *aface)
18    FT_Error FT_Set_Char_Size (FT_Face aFace, unsigned int size_x, unsigned int size_y, unsigned int res_x, unsigned int res_y)
19
20cdef extern from "hb-common.h" :
21    cdef enum hb_direction_t :
22        HB_DIRECTION_LTR
23        HB_DIRECTION_RTL
24        HB_DIRECTION_TTB
25        HB_DIRECTION_BTT
26    ctypedef unsigned long hb_codepoint_t
27    ctypedef long hb_position_t
28    ctypedef unsigned long hb_mask_t
29    ctypedef unsigned long hb_tag_t
30    hb_tag_t hb_tag_from_string (char *s)
31    ctypedef void (*hb_destroy_func_t) (void *user_data)
32    ctypedef void *hb_language_t
33    hb_language_t hb_language_from_string(char *str)
34    char * hb_language_to_string(hb_language_t language)
35
36cdef extern from "hb-unicode.h" :
37# there must be a better way of syncing this list with the true source
38    ctypedef enum hb_script_t :
39        HB_SCRIPT_COMMON = 0
40
41cdef extern from "hb-ot-tag.h" :
42    hb_script_t hb_ot_tag_to_script (hb_tag_t tag)
43
44cdef extern from "hb-buffer.h" :
45    ctypedef struct hb_buffer_t :
46        pass
47
48    ctypedef struct hb_glyph_info_t :
49        hb_codepoint_t codepoint
50        hb_mask_t mask
51        unsigned long cluster
52
53    ctypedef union hb_var_int_t:
54        unsigned long u32
55
56    ctypedef struct hb_glyph_position_t :
57        hb_position_t x_advance
58        hb_position_t y_advance
59        hb_position_t x_offset
60        hb_position_t y_offset
61        hb_var_int_t  var
62
63    hb_buffer_t *hb_buffer_create(unsigned int size)
64    hb_buffer_t *hb_buffer_reference(hb_buffer_t *buffer)
65    unsigned int hb_buffer_get_reference_count(hb_buffer_t *buffer)
66    void hb_buffer_destroy(hb_buffer_t *buffer)
67    void hb_buffer_set_direction(hb_buffer_t *buffer, hb_direction_t direction)
68    hb_direction_t hb_buffer_get_direction(hb_buffer_t *buffer)
69    void hb_buffer_set_script(hb_buffer_t *buffer, hb_script_t script)
70    hb_script_t hb_buffer_get_script(hb_buffer_t *buffer)
71    void hb_buffer_set_language(hb_buffer_t *buffer, hb_language_t language)
72    hb_language_t hb_buffer_get_language(hb_buffer_t *buffer)
73    void hb_buffer_clear(hb_buffer_t *)
74    void hb_buffer_clear_positions(hb_buffer_t *buffer)
75    void hb_buffer_ensure(hb_buffer_t *buffer, unsigned int size)
76    void hb_buffer_reverse(hb_buffer_t *buffer)
77    void hb_buffer_reverse_clusters(hb_buffer_t *buffer)
78    void hb_buffer_add_glyph(hb_buffer_t *buffer, hb_codepoint_t codepoint, hb_mask_t mask, unsigned int cluster)
79    void hb_buffer_add_utf8(hb_buffer_t *buffer, char *text, unsigned int text_length, unsigned int item_offset, unsigned int item_length)
80    unsigned int hb_buffer_get_length(hb_buffer_t *buffer)
81    hb_glyph_info_t *hb_buffer_get_glyph_infos(hb_buffer_t *buffer, unsigned int *len)
82    hb_glyph_position_t *hb_buffer_get_glyph_positions(hb_buffer_t *buffer, unsigned int *len)
83
84cdef extern from "hb-blob.h" :
85    cdef struct hb_blob_t :
86        pass
87# do I need blob functions here?
88
89cdef extern from "hb-font.h" :
90    ctypedef struct hb_face_t :
91        pass
92    ctypedef struct hb_font_t :
93        pass
94
95    ctypedef hb_blob_t * (*hb_get_table_func_t) (hb_tag_t tag, void *user_data)
96    hb_face_t * hb_face_create_for_data(hb_blob_t *blob, unsigned int index)
97    hb_face_t * hb_face_create_for_tables(hb_get_table_func_t get_table, hb_destroy_func_t destroy, void *user_data)
98    hb_face_t * hb_face_reference(hb_face_t *face)
99    unsigned int hb_face_get_reference_count(hb_face_t *face)
100    void hb_face_destroy(hb_face_t *face)
101    void hb_font_destroy(hb_font_t *font)
102    hb_blob_t * hb_face_get_table(hb_face_t *face, hb_tag_t tag)
103
104
105cdef extern from "hb-shape.h" :
106    ctypedef struct hb_feature_t :
107        int tag
108        unsigned int value
109        unsigned int start
110        unsigned int end
111
112    void hb_shape (hb_font_t *font, hb_buffer_t *buffer, hb_feature_t *features, unsigned int num_features)
113
114cdef extern from "hb-ft.h" :
115    hb_face_t *hb_ft_face_create (FT_Face ft_face, hb_destroy_func_t destroy)
116    hb_font_t *hb_ft_font_create (FT_Face ft_face, hb_destroy_func_t destroy)
117
118class glyphinfo :
119 
120    def __init__(self, gid, cluster, advance, offset, internal = 0) :
121        self.gid = gid
122        self.cluster = cluster
123        self.advance = advance
124        self.offset = offset
125        self.internal = internal
126
127    def __repr__(self) :
128        res = "{0:d}>{1:d}@({2:.2f},{3:.2f})+({4:.2f},{5:.2f})".format(self.gid, self.cluster, self.offset[0], self.offset[1], self.advance[0], self.advance[1])
129        if self.internal : res += "/i=" + str(self.internal)
130        return res
131
132cdef class buffer :
133    cdef hb_buffer_t *buffer
134
135    def __init__(self, char *text, unsigned int length) :
136        """Note text must be a utf-8 string and length is number of chars"""
137        self.buffer = hb_buffer_create(length)
138        hb_buffer_add_utf8(self.buffer, text, length, 0, len(text))
139
140    def set_scriptlang(self, char *script, char *lang) :
141        cdef hb_language_t language
142        cdef hb_script_t scriptnum
143
144        language = hb_language_from_string(lang)
145        scriptnum = hb_ot_tag_to_script(hb_tag_from_string(script))
146        hb_buffer_set_script(self.buffer, scriptnum)
147        hb_buffer_set_language(self.buffer, language)
148
149    def get_info(self, scale = 1) :
150        cdef hb_glyph_info_t *infos
151        cdef hb_glyph_position_t *positions
152        cdef unsigned int num
153        cdef unsigned int i
154        res = []
155
156        num = hb_buffer_get_length(self.buffer)
157        infos = hb_buffer_get_glyph_infos(self.buffer, &num)
158        positions = hb_buffer_get_glyph_positions(self.buffer, &num)
159        for 0 <= i < num :
160            temp = glyphinfo(infos[i].codepoint, infos[i].cluster, (positions[i].x_advance / scale, positions[i].y_advance / scale), (positions[i].x_offset / scale, positions[i].y_offset / scale), positions[i].var.u32)
161            res.append(temp)
162        return res
163
164    def get_settings(self) :
165        cdef hb_script_t script
166        cdef hb_language_t lang
167
168        script = hb_buffer_get_script(self.buffer)
169        lang = hb_buffer_get_language(self.buffer)
170        return {'script' : script, 'language' : hb_language_to_string(lang)}
171
172    def __del__(self) :
173        hb_buffer_destroy(self.buffer)
174
175cdef class ft :
176    cdef FT_Library engine
177    cdef FT_Face face
178    cdef hb_face_t *hbface
179    cdef hb_font_t *hbfont
180
181    def __init__(self, char *fname, size) :
182        cdef FT_Library engine
183        FT_Init_FreeType(&engine)
184        self.engine = engine
185        cdef FT_Face face
186        FT_New_Face(engine, fname, 0, &face)
187        FT_Set_Char_Size(face, size << 6, size << 6, 72, 72)
188        self.face = face
189        self.hbface = hb_ft_face_create(face, <void (*)(void *)>hb_face_destroy)
190        self.hbfont = hb_ft_font_create(face, <void (*)(void *)>hb_font_destroy)
191
192    def __del__(self) :
193        cdef FT_Library engine
194        engine = self.engine
195        cdef FT_Face face
196        face = self.face
197        FT_Done_Face(face)
198        FT_Done_FreeType(engine)
199
200    def shape(self, buffer aBuffer, features = {}) :
201        cdef hb_feature_t *feats
202        cdef hb_feature_t *aFeat
203        feats = <hb_feature_t *>malloc(sizeof(hb_feature_t) * len(features))
204        aFeat = feats
205        for k,v in features.items() :
206            aFeat.tag = hb_tag_from_string (k)
207            aFeat.value = int(v)
208            aFeat.start = 0
209            aFeat.end = -1
210            aFeat += 1
211        hb_shape(self.hbfont, aBuffer.buffer, feats, len(features))
212
213
214