freetype 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,149 @@
1
+ require 'freetype/api'
2
+
3
+ module FreeTypeApiTest
4
+ include FreeType::API
5
+
6
+ def libopen
7
+ Library.open do |lib|
8
+ ['data/Prida01.otf', 'data/Starjedi.ttf'].each do |font|
9
+ lib.face_open(font) do |f|
10
+ f.set_char_size(0, 0, 300, 300)
11
+ yield f
12
+ end
13
+ end
14
+ end
15
+ end
16
+
17
+ def test_Library(t)
18
+ lib = nil
19
+ ret = Library.open do |l|
20
+ lib = l
21
+
22
+ unless /\A\d+\.\d+\.\d+\z/.match l.version
23
+ t.error "return value break got #{l.version}"
24
+ end
25
+
26
+ :abc
27
+ end
28
+ if lib.nil?
29
+ t.error('cannot get FT_Library in `open` with block')
30
+ end
31
+ if ret != :abc
32
+ t.error 'want to return last value in block'
33
+ end
34
+ end
35
+
36
+ def test_Face(t)
37
+ face = nil
38
+ Library.open do |lib|
39
+ ['data/Prida01.otf', 'data/Starjedi.ttf'].each do |font|
40
+ lib.face_open(font) do |f|
41
+ face = f
42
+ if f.char_index('a') == 0
43
+ t.error('ascii char not defined this font')
44
+ end
45
+ if f.char_index('㍿') != 0
46
+ t.error("I don't know why set character was defined in font")
47
+ end
48
+
49
+ v = f.kerning('A', 'W')
50
+ unless v
51
+ t.error('#kerning return object was changed')
52
+ end
53
+ unless Fixnum === v.x && Fixnum === v.y
54
+ t.error('Not vector object. Check spec for FT_Get_Kerning()')
55
+ end
56
+
57
+ if /darwin/ =~ RUBY_PLATFORM
58
+ begin
59
+ err = StringIO.new
60
+ origerr = $stderr
61
+ $stderr = err
62
+ f.glyph('a')
63
+ rescue FreeType::Error::Invalid_Size_Handle
64
+ if err.string.empty?
65
+ t.error('recommend warn miss?')
66
+ end
67
+ else
68
+ t.error('check freetype spec')
69
+ ensure
70
+ $stderr = origerr
71
+ end
72
+ end
73
+
74
+ f.set_char_size(0, 0, 300, 300)
75
+
76
+ bbox = f.bbox
77
+ unless BBox === bbox
78
+ t.error('FreeType::API::Face#bbox return value was break')
79
+ end
80
+
81
+ unless Glyph === f.glyph('a')
82
+ t.error 'return value was break'
83
+ end
84
+
85
+ # unless Glyph === f.notdef
86
+ # t.error 'return value was break'
87
+ # end
88
+ end
89
+ end
90
+ end
91
+ if face.nil?
92
+ t.error('cannot get FT_Face in `open` with block')
93
+ end
94
+ end
95
+
96
+ def test_glyph(t)
97
+ libopen do |f|
98
+ table = { 'a' => nil, 'b' => nil, 'c' => nil, 'd' => nil }
99
+ table.each do |char, _|
100
+ glyph = f.glyph(char)
101
+
102
+ metrics = glyph.metrics
103
+ unless FreeType::C::FT_Glyph_Metrics === metrics
104
+ t.error 'return value was break'
105
+ end
106
+
107
+ space_width = glyph.space_width
108
+ unless Fixnum === space_width
109
+ t.error 'return value was break'
110
+ end
111
+
112
+ outline = glyph.outline
113
+ unless Outline === outline
114
+ t.error('FreeType::API::Face#outline return value was break')
115
+ end
116
+ end
117
+ end
118
+ end
119
+
120
+ def test_outline(t)
121
+ libopen do |f|
122
+ table = { 'a' => nil, 'b' => nil, 'c' => nil, 'd' => nil }
123
+ table.each do |char, _|
124
+ outline = f.glyph(char).outline
125
+
126
+ unless 0 < outline.points.length
127
+ t.error('FT_Outline.points get failed from ffi')
128
+ end
129
+
130
+ unless outline.points.all? { |i| Point === i }
131
+ t.error('Miss array of FreeType::API::Outline#points objects assignment')
132
+ end
133
+
134
+ unless outline.tags.all? { |i| Fixnum === i }
135
+ t.error('Got values miss assigned from ffi')
136
+ end
137
+
138
+ unless outline.contours.all? { |i| Fixnum === i }
139
+ t.error('Got values miss assigned from ffi')
140
+ end
141
+
142
+ table[char] = outline.points.map(&:x)
143
+ end
144
+ if table.values.uniq.length != table.length
145
+ t.error 'char reference miss'
146
+ end
147
+ end
148
+ end
149
+ end
@@ -0,0 +1,243 @@
1
+ require 'ffi'
2
+
3
+ module FreeType
4
+ # low level APIs call by FFI
5
+ module C
6
+ extend ::FFI::Library
7
+ ffi_lib ['libfreetype.dylib', 'libfreetype.6.dylib', 'freetype.so', 'freetype.so.6', 'freetype']
8
+ typedef :long, :FT_Pos
9
+ typedef :long, :FT_Fixed
10
+ typedef :long, :FT_F26Dot6
11
+ typedef :int, :FT_Error
12
+
13
+ FT_ENC_TAG = lambda do |a, b, c, d|
14
+ [a, b, c, d].map(&:ord).inject(0) { |r, i| (r << 8) + i }
15
+ end
16
+
17
+ FT_IMAGE_TAG = FT_ENC_TAG
18
+
19
+ # http://www.freetype.org/freetype2/docs/reference/ft2-basic_types.html#FT_Glyph_Format
20
+ FT_Glyph_Format = enum(
21
+ :FT_GLYPH_FORMAT_NONE, 0,
22
+ :FT_GLYPH_FORMAT_COMPOSITE, FT_IMAGE_TAG['c', 'o', 'm', 'p'],
23
+ :FT_GLYPH_FORMAT_BITMAP, FT_IMAGE_TAG['b', 'i', 't', 's'],
24
+ :FT_GLYPH_FORMAT_OUTLINE, FT_IMAGE_TAG['o', 'u', 't', 'l'],
25
+ :FT_GLYPH_FORMAT_PLOTTER, FT_IMAGE_TAG['p', 'l', 'o', 't'],
26
+ )
27
+
28
+ # http://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#FT_Kerning_Mode
29
+ FT_Kerning_Mode = enum(
30
+ :FT_KERNING_DEFAULT, 0,
31
+ :FT_KERNING_UNFITTED,
32
+ :FT_KERNING_UNSCALED,
33
+ )
34
+
35
+ FT_Encoding = enum(
36
+ :FT_ENCODING_NONE, 0,
37
+ :FT_ENCODING_MS_SYMBOL, FT_ENC_TAG['s', 'y', 'm', 'b'],
38
+ :FT_ENCODING_UNICODE, FT_ENC_TAG['u', 'n', 'i', 'c'],
39
+ :FT_ENCODING_SJIS, FT_ENC_TAG['s', 'j', 'i', 's'],
40
+ :FT_ENCODING_GB2312, FT_ENC_TAG['g', 'b', ' ', ' '],
41
+ :FT_ENCODING_BIG5, FT_ENC_TAG['b', 'i', 'g', '5'],
42
+ :FT_ENCODING_WANSUNG, FT_ENC_TAG['w', 'a', 'n', 's'],
43
+ :FT_ENCODING_JOHAB, FT_ENC_TAG['j', 'o', 'h', 'a'],
44
+ :FT_ENCODING_ADOBE_STANDARD, FT_ENC_TAG['A', 'D', 'O', 'B'],
45
+ :FT_ENCODING_ADOBE_EXPERT, FT_ENC_TAG['A', 'D', 'B', 'E'],
46
+ :FT_ENCODING_ADOBE_CUSTOM, FT_ENC_TAG['A', 'D', 'B', 'C'],
47
+ :FT_ENCODING_ADOBE_LATIN_1, FT_ENC_TAG['l', 'a', 't', '1'],
48
+ :FT_ENCODING_OLD_LATIN_2, FT_ENC_TAG['l', 'a', 't', '2'],
49
+ :FT_ENCODING_APPLE_ROMAN, FT_ENC_TAG['a', 'r', 'm', 'n'],
50
+ )
51
+
52
+ # http://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#FT_LOAD_XXX
53
+ FT_LOAD_DEFAULT = 0x0
54
+ FT_LOAD_NO_SCALE = 1 << 0
55
+ FT_LOAD_NO_HINTING = 1 << 1
56
+ FT_LOAD_RENDER = 1 << 2
57
+ FT_LOAD_NO_BITMAP = 1 << 3
58
+ FT_LOAD_VERTICAL_LAYOUT = 1 << 4
59
+ FT_LOAD_FORCE_AUTOHINT = 1 << 5
60
+ FT_LOAD_CROP_BITMAP = 1 << 6
61
+ FT_LOAD_PEDANTIC = 1 << 7
62
+ FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH = 1 << 9
63
+ FT_LOAD_NO_RECURSE = 1 << 10
64
+ FT_LOAD_IGNORE_TRANSFORM = 1 << 11
65
+ FT_LOAD_MONOCHROME = 1 << 12
66
+ FT_LOAD_LINEAR_DESIGN = 1 << 13
67
+ FT_LOAD_NO_AUTOHINT = 1 << 15
68
+ FT_LOAD_COLOR = 1 << 20
69
+ FT_LOAD_COMPUTE_METRICS = 1 << 21
70
+
71
+ # http://www.freetype.org/freetype2/docs/reference/ft2-basic_types.html#FT_BBox
72
+ class FT_BBox < ::FFI::Struct
73
+ layout xMin: :FT_Pos,
74
+ yMin: :FT_Pos,
75
+ xMax: :FT_Pos,
76
+ yMax: :FT_Pos
77
+ end
78
+
79
+ # http://www.freetype.org/freetype2/docs/reference/ft2-basic_types.html#FT_Bitmap
80
+ class FT_Bitmap < ::FFI::Struct
81
+ layout rows: :uint,
82
+ width: :uint,
83
+ pitch: :int,
84
+ buffer: :pointer,
85
+ num_grays: :ushort,
86
+ pixel_mode: :char,
87
+ palette_mode: :char,
88
+ palette: :pointer
89
+ end
90
+
91
+ # http://www.freetype.org/freetype2/docs/reference/ft2-basic_types.html#FT_Generic
92
+ class FT_Generic < ::FFI::Struct
93
+ layout data: :pointer,
94
+ finalizer: :pointer
95
+ end
96
+
97
+ # http://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#FT_Glyph_Metrics
98
+ class FT_Glyph_Metrics < ::FFI::Struct
99
+ layout width: :FT_Pos,
100
+ height: :FT_Pos,
101
+ horiBearingX: :FT_Pos,
102
+ horiBearingY: :FT_Pos,
103
+ horiAdvance: :FT_Pos,
104
+ vertBearingX: :FT_Pos,
105
+ vertBearingY: :FT_Pos,
106
+ vertAdvance: :FT_Pos
107
+ end
108
+
109
+ # http://www.freetype.org/freetype2/docs/reference/ft2-outline_processing.html#FT_Outline
110
+ class FT_Outline < ::FFI::Struct
111
+ layout n_contours: :short,
112
+ n_points: :short,
113
+ points: :pointer, # FT_Vector* (n_points)
114
+ tags: :pointer, # char * (n_points)
115
+ contours: :pointer, # short * (n_contours)
116
+ # http://www.freetype.org/freetype2/docs/reference/ft2-outline_processing.html#FT_OUTLINE_XXX
117
+ flags: :int
118
+ end
119
+
120
+ # http://www.freetype.org/freetype2/docs/reference/ft2-basic_types.html#FT_Vector
121
+ class FT_Vector < ::FFI::Struct
122
+ layout x: :FT_Pos,
123
+ y: :FT_Pos
124
+ end
125
+
126
+ # http://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#FT_GlyphSlotRec
127
+ class FT_GlyphSlotRec < ::FFI::Struct
128
+ layout library: :pointer,
129
+ face: :pointer,
130
+ next: :pointer,
131
+ reserved: :uint,
132
+ generic: FT_Generic,
133
+ metrics: FT_Glyph_Metrics,
134
+ linearHoriAdvance: :FT_Fixed,
135
+ linearVertAdvance: :FT_Fixed,
136
+ advance: FT_Vector,
137
+ format: FT_Glyph_Format,
138
+ bitmap: FT_Bitmap,
139
+ bitmap_left: :int,
140
+ bitmap_top: :int,
141
+ outline: FT_Outline,
142
+ num_subglyphs: :uint,
143
+ subglyphs: :pointer, # FT_SubGlyph
144
+ control_data: :pointer, # void *
145
+ control_len: :long,
146
+ lsb_delta: :FT_Pos,
147
+ rsb_delta: :FT_Pos,
148
+ other: :pointer, # void *
149
+ internal: :pointer # FT_Slot_Internal
150
+ end
151
+
152
+ # http://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#FT_Size_Metrics
153
+ class FT_Size_Metrics < ::FFI::Struct
154
+ layout x_ppem: :ushort,
155
+ y_ppem: :ushort,
156
+ x_scale: :FT_Fixed,
157
+ y_scale: :FT_Fixed,
158
+ ascender: :FT_Pos,
159
+ descender: :FT_Pos,
160
+ height: :FT_Pos,
161
+ max_advance: :FT_Pos
162
+ end
163
+
164
+ # http://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#FT_SizeRec
165
+ class FT_SizeRec < ::FFI::Struct
166
+ layout face: :pointer, # FT_Face
167
+ generic: FT_Generic,
168
+ metrics: FT_Size_Metrics,
169
+ internal: :pointer # FT_Size_Internal
170
+ end
171
+
172
+ class FT_CharMapRec < ::FFI::Struct
173
+ layout face: :pointer,
174
+ encoding: FT_Encoding,
175
+ platform_id: :ushort,
176
+ encoding_id: :ushort
177
+ end
178
+
179
+ # http://www.freetype.org/freetype2/docs/reference/ft2-base_interface.html#FT_FaceRec
180
+ class FT_FaceRec < ::FFI::Struct
181
+ layout num_faces: :long,
182
+ face_index: :long,
183
+ face_flags: :long,
184
+ style_flags: :long,
185
+ num_glyphs: :long,
186
+ family_name: :string,
187
+ style_name: :string,
188
+ num_fixed_sizes: :int,
189
+ available_sizes: :pointer, # FT_Bitmap_Size*
190
+ num_charmaps: :int,
191
+ charmaps: FT_CharMapRec.ptr,
192
+ generic: FT_Generic,
193
+ bbox: FT_BBox,
194
+ units_per_EM: :ushort,
195
+ ascender: :short,
196
+ descender: :short,
197
+ height: :short,
198
+ max_advance_width: :short,
199
+ max_advance_height: :short,
200
+ underline_position: :short,
201
+ underline_thickness: :short,
202
+ glyph: FT_GlyphSlotRec.ptr,
203
+ size: FT_SizeRec.ptr,
204
+ charmap: :pointer
205
+ end
206
+
207
+ # library = FFI::MemoryPointer.new(:pointer)
208
+ # err = FT_Init_FreeType(library)
209
+ # err = FT_Done_Library(library.get_pointer(0))
210
+ attach_function :FT_Init_FreeType, [:pointer], :FT_Error
211
+ attach_function :FT_Done_Library, [:pointer], :FT_Error
212
+ attach_function :FT_Library_Version, [:pointer, :pointer, :pointer, :pointer], :void
213
+
214
+ # face = FFI::MemoryPointer.new(:pointer)
215
+ # err = FT_New_Face(library.get_pointer(0), 'font.otf', 0, face)
216
+ # face = FT_FaceRec.new(face.get_pointer(0))
217
+ # err = FT_Done_Face(face)
218
+ attach_function :FT_New_Face, [:pointer, :string, :long, :pointer], :FT_Error
219
+ attach_function :FT_Done_Face, [:pointer], :FT_Error
220
+
221
+ # err = FT_Set_Char_Size(face, 0, 36 * 64, 300, 300)
222
+ attach_function :FT_Set_Char_Size, [:pointer, :FT_F26Dot6, :FT_F26Dot6, :uint, :uint], :FT_Error
223
+
224
+ # err = FT_Select_Charmap(face, :FT_ENCODING_UNICODE)
225
+ attach_function :FT_Select_Charmap, [:pointer, FT_Encoding], :FT_Error
226
+
227
+ # err = FT_Load_Char(face, 'Q'.ord, FreeType::FT_LOAD_DEFAULT)
228
+ attach_function :FT_Load_Char, [:pointer, :ulong, :int32], :FT_Error
229
+
230
+ # err = FT_Load_Glyph(face, 0, FT_LOAD_DEFAULT)
231
+ # attach_function :FT_Load_Glyph, [FT_FaceRec.ptr, :uint, :int32], :FT_Error
232
+ # attach_function :FT_Get_Glyph, [FT_GlyphSlotRec.ptr, :pointer], :FT_Error
233
+ # attach_function :FT_Done_Glyph, [:pointer], :void
234
+
235
+ # id = FT_Get_Char_Index(face, 'A'.ord) -> glyph id or 0 (undefined)
236
+ attach_function :FT_Get_Char_Index, [:pointer, :ulong], :uint
237
+
238
+ # v = FT_Vector.new
239
+ # err = FT_Get_Kerning(face, before_id, id, :FT_KERNING_DEFAULT, v)
240
+ # p v
241
+ attach_function :FT_Get_Kerning, [:pointer, :uint, :uint, :uint, :pointer], :FT_Error
242
+ end
243
+ end
@@ -0,0 +1,173 @@
1
+ require 'freetype/c'
2
+
3
+ module FFITest
4
+ include FreeType::C
5
+
6
+ FONTS = ['data/Prida01.otf', 'data/Starjedi.ttf']
7
+
8
+ def libopen
9
+ library = ::FFI::MemoryPointer.new(:pointer)
10
+ err = FT_Init_FreeType(library)
11
+ raise FreeType::Error.find(err) unless err == 0
12
+
13
+ FONTS.each do |font|
14
+ face = ::FFI::MemoryPointer.new(:pointer)
15
+ err = FT_New_Face(library.get_pointer(0), font, 0, face)
16
+ raise FreeType::Error.find(err) unless err == 0
17
+
18
+ yield FT_FaceRec.new(face.get_pointer(0)), font
19
+ end
20
+ end
21
+
22
+ def test_Library(t)
23
+ library = ::FFI::MemoryPointer.new(:pointer)
24
+ err = FT_Init_FreeType(library)
25
+ if err != 0
26
+ t.fatal FreeType::Error.find(err).message
27
+ end
28
+
29
+ amajor = FFI::MemoryPointer.new(:int)
30
+ aminor = FFI::MemoryPointer.new(:int)
31
+ apatch = FFI::MemoryPointer.new(:int)
32
+ FT_Library_Version(library.get_pointer(0), amajor, aminor, apatch)
33
+ a = [
34
+ amajor.get_int(0),
35
+ aminor.get_int(0),
36
+ apatch.get_int(0),
37
+ ]
38
+ unless a.all? { |i| Fixnum === i }
39
+ t.error 'miss get values from FT_Library_Version()'
40
+ end
41
+ end
42
+
43
+ def test_Face(t)
44
+ library = ::FFI::MemoryPointer.new(:pointer)
45
+ err = FT_Init_FreeType(library)
46
+ if err != 0
47
+ t.fatal FreeType::Error.find(err).message
48
+ end
49
+ FONTS.each do |font|
50
+ face = ::FFI::MemoryPointer.new(:pointer)
51
+ err = FT_New_Face(library.get_pointer(0), font, 0, face)
52
+ if err != 0
53
+ t.fatal FreeType::Error.find(err).message
54
+ end
55
+
56
+ face = FT_FaceRec.new(face.get_pointer(0))
57
+ err = FT_Select_Charmap(face, :FT_ENCODING_UNICODE)
58
+ if err != 0
59
+ t.error FreeType::Error.find(err).message
60
+ end
61
+ end
62
+ end
63
+
64
+ def test_FT_Set_Char_Size(t)
65
+ libopen do |face|
66
+ if /darwin/ =~ RUBY_PLATFORM
67
+ err = FT_Load_Char(face, 'a'.ord, FreeType::C::FT_LOAD_DEFAULT)
68
+ e = FreeType::Error.find(err)
69
+ unless FreeType::Error::Invalid_Size_Handle === e
70
+ t.fatal 'check freetype spec'
71
+ end
72
+ end
73
+
74
+ err = FT_Set_Char_Size(face, 0, 32, 300, 300)
75
+ if err != 0
76
+ t.error FreeType::Error.find(err).message
77
+ end
78
+
79
+ err = FT_Load_Char(face, 'a'.ord, FreeType::C::FT_LOAD_DEFAULT)
80
+ if err != 0
81
+ t.error FreeType::Error.find(err).message
82
+ end
83
+ end
84
+ end
85
+
86
+ def test_char(t)
87
+ libopen do |face, _font|
88
+ err = FT_Set_Char_Size(face, 0, 32, 300, 300)
89
+ if err != 0
90
+ t.fatal FreeType::Error.find(err).message
91
+ end
92
+
93
+ before_glyph_id = nil
94
+ %w(i e f g A W & * @ % - + < >).concat([' ', 'あ', ' ', "\n"]).each do |char|
95
+ glyph_id = FT_Get_Char_Index(face, char.ord)
96
+ if glyph_id == 0
97
+ unless /あ| |\n/.match(char)
98
+ t.error('ascii char is undefined')
99
+ end
100
+ next
101
+ end
102
+
103
+ if before_glyph_id
104
+ v = FT_Vector.new
105
+ err = FT_Get_Kerning(face, before_glyph_id, glyph_id, :FT_KERNING_UNFITTED, v)
106
+ if err != 0
107
+ t.error FreeType::Error.find(err).message
108
+ end
109
+ unless Fixnum === v[:x] && Fixnum === v[:y]
110
+ t.error 'cannot get kerning value from FT_Get_Kerning()'
111
+ end
112
+ end
113
+
114
+ err = FT_Load_Char(face, char.ord, FreeType::C::FT_LOAD_DEFAULT)
115
+ if err != 0
116
+ t.error FreeType::Error.find(err).message
117
+ end
118
+
119
+ size = face[:size]
120
+ unless FT_SizeRec === size
121
+ t.error 'Miss Struct bind'
122
+ end
123
+
124
+ size_metrics = face[:size][:metrics]
125
+ unless FT_Size_Metrics === size_metrics
126
+ t.error 'Miss Struct bind'
127
+ end
128
+
129
+ glyph = face[:glyph]
130
+ unless FT_GlyphSlotRec === glyph
131
+ t.error 'Miss Struct bind'
132
+ end
133
+
134
+ glyph_metrics = face[:glyph][:metrics]
135
+ unless FT_Glyph_Metrics === glyph_metrics
136
+ t.error 'Miss Struct bind'
137
+ end
138
+
139
+ outline = face[:glyph][:outline]
140
+ unless 0 <= outline[:n_points]
141
+ t.error "n_outline:#{outline[:n_points]} Cannot get FT_Outline.n_prints member from ffi"
142
+ end
143
+
144
+ unless 0 <= outline[:n_contours]
145
+ t.error "n_contours:#{outline[:n_contours]} Cannot get FT_Outline.n_contours member from ffi"
146
+ end
147
+
148
+ end_ptd_of_counts = outline[:contours].get_array_of_short(0, outline[:n_contours])
149
+
150
+ unless end_ptd_of_counts.all? { |i| Fixnum === i }
151
+ t.error 'FT_Outline.contours is array if short. broken or fail when get form ffi.'
152
+ end
153
+
154
+ tags = outline[:tags].get_array_of_char(0, outline[:n_points])
155
+ unless tags.all? { |i| Fixnum === i }
156
+ t.error 'FT_Outline.tags is array of char. broken or fail when get form ffi.'
157
+ end
158
+
159
+ points = outline[:n_points].times.map do |i|
160
+ FT_Vector.new(outline[:points] + i * FT_Vector.size)
161
+ end
162
+
163
+ points.each do |i|
164
+ unless i[:x].kind_of?(Fixnum) && i[:y].kind_of?(Fixnum)
165
+ t.error('Miss assignment from ffi')
166
+ end
167
+ end
168
+
169
+ before_glyph_id = glyph_id
170
+ end
171
+ end
172
+ end
173
+ end