Class: HarfBuzz::FontFuncs

Inherits:
Object
  • Object
show all
Defined in:
lib/harfbuzz/font_funcs.rb

Overview

Wraps hb_font_funcs_t — customizable font callback table

FontFuncs allows you to override how HarfBuzz queries glyph data from a font. This is used to implement custom font backends (e.g., connecting to FreeType, CoreText, or a custom renderer).

Examples:

Custom nominal glyph lookup

funcs = HarfBuzz::FontFuncs.new
funcs.on_nominal_glyph do |_font, codepoint|
  my_cmap[codepoint]
end
funcs.make_immutable!
font.set_funcs(funcs)

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeFontFuncs

Returns a new instance of FontFuncs.

Raises:



20
21
22
23
24
25
26
27
# File 'lib/harfbuzz/font_funcs.rb', line 20

def initialize
  @ptr = C.hb_font_funcs_create
  raise AllocationError, "Failed to create font funcs" if @ptr.null?

  # Keep FFI::Function objects alive as long as this object is alive
  @callbacks = {}
  HarfBuzz::FontFuncs.define_finalizer(self, @ptr)
end

Instance Attribute Details

#ptrObject (readonly)

Returns the value of attribute ptr.



18
19
20
# File 'lib/harfbuzz/font_funcs.rb', line 18

def ptr
  @ptr
end

Class Method Details

.define_finalizer(obj, ptr) ⇒ Object



279
280
281
282
283
284
# File 'lib/harfbuzz/font_funcs.rb', line 279

def self.define_finalizer(obj, ptr)
  return if obj.instance_variable_defined?(:@borrowed) && obj.instance_variable_get(:@borrowed)

  destroy = C.method(:hb_font_funcs_destroy)
  ObjectSpace.define_finalizer(obj, proc { destroy.call(ptr) })
end

.emptyFontFuncs

Returns the singleton empty font funcs

Returns:



31
32
33
34
35
36
37
# File 'lib/harfbuzz/font_funcs.rb', line 31

def self.empty
  obj = allocate
  obj.instance_variable_set(:@ptr, C.hb_font_funcs_get_empty)
  obj.instance_variable_set(:@borrowed, true)
  obj.instance_variable_set(:@callbacks, {})
  obj
end

Instance Method Details

#immutable?Boolean

Returns true if immutable.

Returns:

  • (Boolean)

    true if immutable



40
41
42
# File 'lib/harfbuzz/font_funcs.rb', line 40

def immutable?
  C.from_hb_bool(C.hb_font_funcs_is_immutable(@ptr))
end

#inspectObject



275
276
277
# File 'lib/harfbuzz/font_funcs.rb', line 275

def inspect
  "#<HarfBuzz::FontFuncs immutable=#{immutable?}>"
end

#make_immutable!self

Makes the funcs table immutable (required before attaching to a font)

Returns:

  • (self)


46
47
48
49
# File 'lib/harfbuzz/font_funcs.rb', line 46

def make_immutable!
  C.hb_font_funcs_make_immutable(@ptr)
  self
end

#on_draw_glyph {|font, glyph, draw_funcs_ptr, draw_data_ptr| ... } ⇒ Object

Sets the draw glyph callback (called when font draws a glyph via draw funcs)

Yields:

  • (font, glyph, draw_funcs_ptr, draw_data_ptr)

    Called with font pointer, glyph ID, and draw state



266
267
268
269
270
271
272
273
# File 'lib/harfbuzz/font_funcs.rb', line 266

def on_draw_glyph(&block)
  cb = FFI::Function.new(:void, [:pointer, :pointer, :uint32, :pointer, :pointer, :pointer]) do |font_ptr, _font_data, glyph, draw_funcs_ptr, draw_data_ptr, _user_data|
    block.call(font_ptr, glyph, draw_funcs_ptr, draw_data_ptr)
  end
  @callbacks[:draw_glyph] = cb
  C.hb_font_funcs_set_draw_glyph_func(@ptr, cb, nil, nil)
  self
end

#on_font_h_extents {|font| ... } ⇒ Object

Sets the horizontal font extents callback

Yields:

  • (font)

    Called with the HarfBuzz font pointer

Yield Returns:

  • (Hash, nil)

    Hash with :ascender, :descender, :line_gap keys (in font units), or nil



54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/harfbuzz/font_funcs.rb', line 54

def on_font_h_extents(&block)
  cb = FFI::Function.new(:int, [:pointer, :pointer, :pointer, :pointer]) do |font_ptr, _font_data, extents_ptr, _user_data|
    result = block.call(font_ptr)
    next 0 unless result

    extents = C::HbFontExtentsT.new(extents_ptr)
    extents[:ascender] = result[:ascender] || 0
    extents[:descender] = result[:descender] || 0
    extents[:line_gap] = result[:line_gap] || 0
    1
  end
  @callbacks[:font_h_extents] = cb
  C.hb_font_funcs_set_font_h_extents_func(@ptr, cb, nil, nil)
  self
end

#on_font_v_extents {|font| ... } ⇒ Object

Sets the vertical font extents callback

Yields:

  • (font)

    Called with the HarfBuzz font pointer

Yield Returns:

  • (Hash, nil)

    Hash with :ascender, :descender, :line_gap keys, or nil



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
# File 'lib/harfbuzz/font_funcs.rb', line 73

def on_font_v_extents(&block)
  cb = FFI::Function.new(:int, [:pointer, :pointer, :pointer, :pointer]) do |font_ptr, _font_data, extents_ptr, _user_data|
    result = block.call(font_ptr)
    next 0 unless result

    extents = C::HbFontExtentsT.new(extents_ptr)
    extents[:ascender] = result[:ascender] || 0
    extents[:descender] = result[:descender] || 0
    extents[:line_gap] = result[:line_gap] || 0
    1
  end
  @callbacks[:font_v_extents] = cb
  C.hb_font_funcs_set_font_v_extents_func(@ptr, cb, nil, nil)
  self
end

#on_glyph_contour_point {|font, glyph, point_index| ... } ⇒ Object

Sets the glyph contour point callback

Yields:

  • (font, glyph, point_index)

    Called with font pointer, glyph ID, and point index

Yield Returns:

  • (Array<Integer>, nil)

    [x, y] contour point coordinates, or nil if not found



250
251
252
253
254
255
256
257
258
259
260
261
262
# File 'lib/harfbuzz/font_funcs.rb', line 250

def on_glyph_contour_point(&block)
  cb = FFI::Function.new(:int, [:pointer, :pointer, :uint32, :uint, :pointer, :pointer, :pointer]) do |font_ptr, _font_data, glyph, point_index, x_out, y_out, _user_data|
    result = block.call(font_ptr, glyph, point_index)
    next 0 unless result

    x_out.write_int32(result[0])
    y_out.write_int32(result[1])
    1
  end
  @callbacks[:glyph_contour_point] = cb
  C.hb_font_funcs_set_glyph_contour_point_func(@ptr, cb, nil, nil)
  self
end

#on_glyph_extents {|font, glyph| ... } ⇒ Object

Sets the glyph extents callback

Yields:

  • (font, glyph)

    Called with font pointer and glyph ID

Yield Returns:

  • (Hash, nil)

    Hash with :x_bearing, :y_bearing, :width, :height keys, or nil



194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
# File 'lib/harfbuzz/font_funcs.rb', line 194

def on_glyph_extents(&block)
  cb = FFI::Function.new(:int, [:pointer, :pointer, :uint32, :pointer, :pointer]) do |font_ptr, _font_data, glyph, extents_ptr, _user_data|
    result = block.call(font_ptr, glyph)
    next 0 unless result

    extents = C::HbGlyphExtentsT.new(extents_ptr)
    extents[:x_bearing] = result[:x_bearing] || 0
    extents[:y_bearing] = result[:y_bearing] || 0
    extents[:width] = result[:width] || 0
    extents[:height] = result[:height] || 0
    1
  end
  @callbacks[:glyph_extents] = cb
  C.hb_font_funcs_set_glyph_extents_func(@ptr, cb, nil, nil)
  self
end

#on_glyph_from_name {|font, name| ... } ⇒ Object

Sets the glyph-from-name lookup callback

Yields:

  • (font, name)

    Called with font pointer and glyph name string

Yield Returns:

  • (Integer, nil)

    Glyph ID or nil if not found



233
234
235
236
237
238
239
240
241
242
243
244
245
# File 'lib/harfbuzz/font_funcs.rb', line 233

def on_glyph_from_name(&block)
  cb = FFI::Function.new(:int, [:pointer, :pointer, :pointer, :int, :pointer, :pointer]) do |font_ptr, _font_data, name_ptr, name_len, glyph_out, _user_data|
    name = name_len < 0 ? name_ptr.read_string : name_ptr.read_bytes(name_len)
    glyph_id = block.call(font_ptr, name)
    next 0 unless glyph_id

    glyph_out.write_uint32(glyph_id)
    1
  end
  @callbacks[:glyph_from_name] = cb
  C.hb_font_funcs_set_glyph_from_name_func(@ptr, cb, nil, nil)
  self
end

#on_glyph_h_advance {|font, glyph| ... } ⇒ Object

Sets the horizontal glyph advance callback

Yields:

  • (font, glyph)

    Called with font pointer and glyph ID

Yield Returns:

  • (Integer)

    Horizontal advance in font units



124
125
126
127
128
129
130
131
# File 'lib/harfbuzz/font_funcs.rb', line 124

def on_glyph_h_advance(&block)
  cb = FFI::Function.new(:int32, [:pointer, :pointer, :uint32, :pointer]) do |font_ptr, _font_data, glyph, _user_data|
    block.call(font_ptr, glyph).to_i
  end
  @callbacks[:glyph_h_advance] = cb
  C.hb_font_funcs_set_glyph_h_advance_func(@ptr, cb, nil, nil)
  self
end

#on_glyph_h_kerning {|font, left_glyph, right_glyph| ... } ⇒ Object

Sets the horizontal glyph kerning callback

Yields:

  • (font, left_glyph, right_glyph)

    Called with font pointer and two glyph IDs

Yield Returns:

  • (Integer)

    Kerning value in font units



182
183
184
185
186
187
188
189
# File 'lib/harfbuzz/font_funcs.rb', line 182

def on_glyph_h_kerning(&block)
  cb = FFI::Function.new(:int32, [:pointer, :pointer, :uint32, :uint32, :pointer]) do |font_ptr, _font_data, left, right, _user_data|
    block.call(font_ptr, left, right).to_i
  end
  @callbacks[:glyph_h_kerning] = cb
  C.hb_font_funcs_set_glyph_h_kerning_func(@ptr, cb, nil, nil)
  self
end

#on_glyph_h_origin {|font, glyph| ... } ⇒ Object

Sets the horizontal glyph origin callback

Yields:

  • (font, glyph)

    Called with font pointer and glyph ID

Yield Returns:

  • (Array<Integer>, nil)

    [x, y] origin or nil



148
149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/harfbuzz/font_funcs.rb', line 148

def on_glyph_h_origin(&block)
  cb = FFI::Function.new(:int, [:pointer, :pointer, :uint32, :pointer, :pointer, :pointer]) do |font_ptr, _font_data, glyph, x_out, y_out, _user_data|
    result = block.call(font_ptr, glyph)
    next 0 unless result

    x_out.write_int32(result[0])
    y_out.write_int32(result[1])
    1
  end
  @callbacks[:glyph_h_origin] = cb
  C.hb_font_funcs_set_glyph_h_origin_func(@ptr, cb, nil, nil)
  self
end

#on_glyph_name {|font, glyph| ... } ⇒ Object

Sets the glyph name callback

Yields:

  • (font, glyph)

    Called with font pointer and glyph ID

Yield Returns:

  • (String, nil)

    Glyph name or nil



214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
# File 'lib/harfbuzz/font_funcs.rb', line 214

def on_glyph_name(&block)
  cb = FFI::Function.new(:int, [:pointer, :pointer, :uint32, :pointer, :uint, :pointer]) do |font_ptr, _font_data, glyph, name_buf, name_buf_size, _user_data|
    name = block.call(font_ptr, glyph)
    next 0 unless name

    bytes = name.bytesize
    size = [bytes, name_buf_size - 1].min
    name_buf.put_bytes(0, name, 0, size)
    name_buf.put_uint8(size, 0)  # null terminate
    1
  end
  @callbacks[:glyph_name] = cb
  C.hb_font_funcs_set_glyph_name_func(@ptr, cb, nil, nil)
  self
end

#on_glyph_v_advance {|font, glyph| ... } ⇒ Object

Sets the vertical glyph advance callback

Yields:

  • (font, glyph)

    Called with font pointer and glyph ID

Yield Returns:

  • (Integer)

    Vertical advance in font units



136
137
138
139
140
141
142
143
# File 'lib/harfbuzz/font_funcs.rb', line 136

def on_glyph_v_advance(&block)
  cb = FFI::Function.new(:int32, [:pointer, :pointer, :uint32, :pointer]) do |font_ptr, _font_data, glyph, _user_data|
    block.call(font_ptr, glyph).to_i
  end
  @callbacks[:glyph_v_advance] = cb
  C.hb_font_funcs_set_glyph_v_advance_func(@ptr, cb, nil, nil)
  self
end

#on_glyph_v_origin {|font, glyph| ... } ⇒ Object

Sets the vertical glyph origin callback

Yields:

  • (font, glyph)

    Called with font pointer and glyph ID

Yield Returns:

  • (Array<Integer>, nil)

    [x, y] origin or nil



165
166
167
168
169
170
171
172
173
174
175
176
177
# File 'lib/harfbuzz/font_funcs.rb', line 165

def on_glyph_v_origin(&block)
  cb = FFI::Function.new(:int, [:pointer, :pointer, :uint32, :pointer, :pointer, :pointer]) do |font_ptr, _font_data, glyph, x_out, y_out, _user_data|
    result = block.call(font_ptr, glyph)
    next 0 unless result

    x_out.write_int32(result[0])
    y_out.write_int32(result[1])
    1
  end
  @callbacks[:glyph_v_origin] = cb
  C.hb_font_funcs_set_glyph_v_origin_func(@ptr, cb, nil, nil)
  self
end

#on_nominal_glyph {|font, codepoint| ... } ⇒ Object

Sets the nominal glyph lookup callback

Yields:

  • (font, codepoint)

    Called with font pointer and Unicode codepoint

Yield Returns:

  • (Integer, nil)

    Glyph ID or nil if not found



92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/harfbuzz/font_funcs.rb', line 92

def on_nominal_glyph(&block)
  cb = FFI::Function.new(:int, [:pointer, :pointer, :uint32, :pointer, :pointer]) do |font_ptr, _font_data, codepoint, glyph_out, _user_data|
    glyph_id = block.call(font_ptr, codepoint)
    next 0 unless glyph_id

    glyph_out.write_uint32(glyph_id)
    1
  end
  @callbacks[:nominal_glyph] = cb
  C.hb_font_funcs_set_nominal_glyph_func(@ptr, cb, nil, nil)
  self
end

#on_variation_glyph {|font, codepoint, variation_selector| ... } ⇒ Object

Sets the variation glyph lookup callback

Yields:

  • (font, codepoint, variation_selector)

    Called with font pointer, codepoint, and selector

Yield Returns:

  • (Integer, nil)

    Glyph ID or nil if not found



108
109
110
111
112
113
114
115
116
117
118
119
# File 'lib/harfbuzz/font_funcs.rb', line 108

def on_variation_glyph(&block)
  cb = FFI::Function.new(:int, [:pointer, :pointer, :uint32, :uint32, :pointer, :pointer]) do |font_ptr, _font_data, codepoint, selector, glyph_out, _user_data|
    glyph_id = block.call(font_ptr, codepoint, selector)
    next 0 unless glyph_id

    glyph_out.write_uint32(glyph_id)
    1
  end
  @callbacks[:variation_glyph] = cb
  C.hb_font_funcs_set_variation_glyph_func(@ptr, cb, nil, nil)
  self
end