harfbuzz-ruby 1.0.0
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.
- checksums.yaml +7 -0
- data/CHANGELOG.md +12 -0
- data/LICENSE.txt +21 -0
- data/README.md +258 -0
- data/Rakefile +8 -0
- data/benchmark/shaping_bench.rb +77 -0
- data/examples/basic_shaping.rb +67 -0
- data/examples/glyph_outlines.rb +79 -0
- data/examples/opentype_features.rb +91 -0
- data/examples/render_svg.rb +112 -0
- data/examples/render_waterfall.rb +177 -0
- data/examples/variable_fonts.rb +73 -0
- data/lib/harfbuzz/aat/layout.rb +78 -0
- data/lib/harfbuzz/blob.rb +136 -0
- data/lib/harfbuzz/buffer.rb +497 -0
- data/lib/harfbuzz/c/aat/layout.rb +15 -0
- data/lib/harfbuzz/c/base.rb +114 -0
- data/lib/harfbuzz/c/blob.rb +23 -0
- data/lib/harfbuzz/c/buffer.rb +127 -0
- data/lib/harfbuzz/c/common.rb +39 -0
- data/lib/harfbuzz/c/draw.rb +22 -0
- data/lib/harfbuzz/c/enums.rb +146 -0
- data/lib/harfbuzz/c/face.rb +37 -0
- data/lib/harfbuzz/c/font.rb +88 -0
- data/lib/harfbuzz/c/font_funcs.rb +58 -0
- data/lib/harfbuzz/c/map.rb +28 -0
- data/lib/harfbuzz/c/ot/color.rb +32 -0
- data/lib/harfbuzz/c/ot/font.rb +7 -0
- data/lib/harfbuzz/c/ot/layout.rb +83 -0
- data/lib/harfbuzz/c/ot/math.rb +23 -0
- data/lib/harfbuzz/c/ot/meta.rb +10 -0
- data/lib/harfbuzz/c/ot/metrics.rb +16 -0
- data/lib/harfbuzz/c/ot/name.rb +13 -0
- data/lib/harfbuzz/c/ot/shape.rb +10 -0
- data/lib/harfbuzz/c/ot/var.rb +22 -0
- data/lib/harfbuzz/c/paint.rb +38 -0
- data/lib/harfbuzz/c/set.rb +42 -0
- data/lib/harfbuzz/c/shape.rb +11 -0
- data/lib/harfbuzz/c/shape_plan.rb +24 -0
- data/lib/harfbuzz/c/structs.rb +120 -0
- data/lib/harfbuzz/c/subset.rb +49 -0
- data/lib/harfbuzz/c/unicode.rb +40 -0
- data/lib/harfbuzz/c/version.rb +25 -0
- data/lib/harfbuzz/draw_funcs.rb +112 -0
- data/lib/harfbuzz/error.rb +27 -0
- data/lib/harfbuzz/face.rb +186 -0
- data/lib/harfbuzz/feature.rb +76 -0
- data/lib/harfbuzz/flags.rb +85 -0
- data/lib/harfbuzz/font.rb +404 -0
- data/lib/harfbuzz/font_funcs.rb +286 -0
- data/lib/harfbuzz/glyph_info.rb +35 -0
- data/lib/harfbuzz/glyph_position.rb +41 -0
- data/lib/harfbuzz/library.rb +98 -0
- data/lib/harfbuzz/map.rb +157 -0
- data/lib/harfbuzz/ot/color.rb +125 -0
- data/lib/harfbuzz/ot/font.rb +16 -0
- data/lib/harfbuzz/ot/layout.rb +583 -0
- data/lib/harfbuzz/ot/math.rb +111 -0
- data/lib/harfbuzz/ot/meta.rb +34 -0
- data/lib/harfbuzz/ot/metrics.rb +54 -0
- data/lib/harfbuzz/ot/name.rb +81 -0
- data/lib/harfbuzz/ot/shape.rb +34 -0
- data/lib/harfbuzz/ot/var.rb +116 -0
- data/lib/harfbuzz/paint_funcs.rb +134 -0
- data/lib/harfbuzz/set.rb +272 -0
- data/lib/harfbuzz/shape_plan.rb +115 -0
- data/lib/harfbuzz/shaping_result.rb +94 -0
- data/lib/harfbuzz/subset.rb +130 -0
- data/lib/harfbuzz/unicode_funcs.rb +201 -0
- data/lib/harfbuzz/variation.rb +49 -0
- data/lib/harfbuzz/version.rb +5 -0
- data/lib/harfbuzz-ffi.rb +4 -0
- data/lib/harfbuzz.rb +313 -0
- data/sig/harfbuzz.rbs +594 -0
- metadata +132 -0
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module HarfBuzz
|
|
4
|
+
# Wraps hb_glyph_info_t, providing access to glyph ID and cluster index
|
|
5
|
+
class GlyphInfo
|
|
6
|
+
def initialize(struct_ptr)
|
|
7
|
+
@struct = C::HbGlyphInfoT.new(struct_ptr)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
# @return [Integer] Glyph ID (after shaping) or Unicode codepoint (before shaping)
|
|
11
|
+
def codepoint
|
|
12
|
+
@struct[:codepoint]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
alias glyph_id codepoint
|
|
16
|
+
|
|
17
|
+
# @return [Integer] Cluster index in source text
|
|
18
|
+
def cluster
|
|
19
|
+
@struct[:cluster]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# @return [Integer] Glyph flags bitmask
|
|
23
|
+
def mask
|
|
24
|
+
@struct[:mask]
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def to_h
|
|
28
|
+
{ codepoint: codepoint, cluster: cluster, mask: mask }
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def inspect
|
|
32
|
+
"#<HarfBuzz::GlyphInfo glyph_id=#{codepoint} cluster=#{cluster}>"
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module HarfBuzz
|
|
4
|
+
# Wraps hb_glyph_position_t, providing access to advance and offset values
|
|
5
|
+
class GlyphPosition
|
|
6
|
+
def initialize(struct_ptr)
|
|
7
|
+
@struct = C::HbGlyphPositionT.new(struct_ptr)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
# @return [Integer] Horizontal advance (in font units)
|
|
11
|
+
def x_advance
|
|
12
|
+
@struct[:x_advance]
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# @return [Integer] Vertical advance (in font units)
|
|
16
|
+
def y_advance
|
|
17
|
+
@struct[:y_advance]
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# @return [Integer] Horizontal offset (in font units)
|
|
21
|
+
def x_offset
|
|
22
|
+
@struct[:x_offset]
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# @return [Integer] Vertical offset (in font units)
|
|
26
|
+
def y_offset
|
|
27
|
+
@struct[:y_offset]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def to_h
|
|
31
|
+
{
|
|
32
|
+
x_advance: x_advance, y_advance: y_advance,
|
|
33
|
+
x_offset: x_offset, y_offset: y_offset
|
|
34
|
+
}
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def inspect
|
|
38
|
+
"#<HarfBuzz::GlyphPosition adv=(#{x_advance},#{y_advance}) off=(#{x_offset},#{y_offset})>"
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rbconfig"
|
|
4
|
+
|
|
5
|
+
module HarfBuzz
|
|
6
|
+
# Returns the path to the HarfBuzz shared library
|
|
7
|
+
# @return [String, Array<String>] Library path or array of library names for FFI to search
|
|
8
|
+
def self.library_path
|
|
9
|
+
@library_path ||= detect_library
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
# Sets the library path explicitly
|
|
13
|
+
# @param path [String] Path to the HarfBuzz shared library
|
|
14
|
+
def self.library_path=(path)
|
|
15
|
+
@library_path = path
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Detects the HarfBuzz shared library location
|
|
19
|
+
# @return [String, Array<String>] Library path or array of library names
|
|
20
|
+
# @raise [LibraryNotFoundError] If library cannot be found
|
|
21
|
+
private_class_method def self.detect_library
|
|
22
|
+
# 1. Environment variable override
|
|
23
|
+
if (env_path = ENV.fetch("HARFBUZZ_LIB_PATH", nil))
|
|
24
|
+
return env_path if File.exist?(env_path)
|
|
25
|
+
|
|
26
|
+
warn "HARFBUZZ_LIB_PATH=#{env_path} does not exist, falling back to auto-detection"
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
# 2. pkg-config (most reliable)
|
|
30
|
+
pkg_config_path = try_pkg_config
|
|
31
|
+
return pkg_config_path if pkg_config_path
|
|
32
|
+
|
|
33
|
+
# 3. Platform-specific default paths
|
|
34
|
+
platform_path = try_platform_paths
|
|
35
|
+
return platform_path if platform_path
|
|
36
|
+
|
|
37
|
+
# 4. Let FFI search via ldconfig / dyld (return array of library names)
|
|
38
|
+
["harfbuzz", "libharfbuzz", "libharfbuzz-0"]
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Tries to find library path using pkg-config
|
|
42
|
+
# @return [String, nil] Library path if found
|
|
43
|
+
private_class_method def self.try_pkg_config
|
|
44
|
+
# Suppress mkmf output
|
|
45
|
+
libs = `pkg-config --libs harfbuzz 2>/dev/null`.strip
|
|
46
|
+
return nil if libs.empty?
|
|
47
|
+
|
|
48
|
+
lib_dir = libs[/-L(\S+)/, 1]
|
|
49
|
+
return nil unless lib_dir
|
|
50
|
+
|
|
51
|
+
ext = lib_extension
|
|
52
|
+
path = File.join(lib_dir, "libharfbuzz.#{ext}")
|
|
53
|
+
File.exist?(path) ? path : nil
|
|
54
|
+
rescue StandardError
|
|
55
|
+
nil
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# Tries platform-specific library paths
|
|
59
|
+
# @return [String, nil] Library path if found
|
|
60
|
+
private_class_method def self.try_platform_paths
|
|
61
|
+
candidates = case RbConfig::CONFIG["host_os"]
|
|
62
|
+
when /darwin/i
|
|
63
|
+
%w[
|
|
64
|
+
/opt/homebrew/lib/libharfbuzz.dylib
|
|
65
|
+
/usr/local/lib/libharfbuzz.dylib
|
|
66
|
+
/opt/local/lib/libharfbuzz.dylib
|
|
67
|
+
]
|
|
68
|
+
when /linux/i
|
|
69
|
+
%w[
|
|
70
|
+
/usr/lib/x86_64-linux-gnu/libharfbuzz.so
|
|
71
|
+
/usr/lib/aarch64-linux-gnu/libharfbuzz.so
|
|
72
|
+
/usr/lib64/libharfbuzz.so
|
|
73
|
+
/usr/lib/libharfbuzz.so
|
|
74
|
+
/usr/local/lib/libharfbuzz.so
|
|
75
|
+
]
|
|
76
|
+
when /mingw|mswin|cygwin/i
|
|
77
|
+
%w[
|
|
78
|
+
C:/msys64/mingw64/bin/libharfbuzz-0.dll
|
|
79
|
+
C:/msys64/ucrt64/bin/libharfbuzz-0.dll
|
|
80
|
+
C:/msys64/clang64/bin/libharfbuzz-0.dll
|
|
81
|
+
]
|
|
82
|
+
else
|
|
83
|
+
[]
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
candidates.find { |p| File.exist?(p) }
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Returns the library extension for the current platform
|
|
90
|
+
# @return [String] Library extension (.dylib, .so, or .dll)
|
|
91
|
+
private_class_method def self.lib_extension
|
|
92
|
+
case RbConfig::CONFIG["host_os"]
|
|
93
|
+
when /darwin/i then "dylib"
|
|
94
|
+
when /mingw|mswin|cygwin/i then "dll"
|
|
95
|
+
else "so"
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
data/lib/harfbuzz/map.rb
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module HarfBuzz
|
|
4
|
+
# Wraps hb_map_t — an integer-to-integer mapping
|
|
5
|
+
#
|
|
6
|
+
# Behaves similarly to Ruby's Hash with Integer keys and values.
|
|
7
|
+
# Includes Enumerable.
|
|
8
|
+
class Map
|
|
9
|
+
include Enumerable
|
|
10
|
+
|
|
11
|
+
HB_MAP_VALUE_INVALID = 0xFFFFFFFF
|
|
12
|
+
|
|
13
|
+
attr_reader :ptr
|
|
14
|
+
|
|
15
|
+
def initialize
|
|
16
|
+
@ptr = C.hb_map_create
|
|
17
|
+
raise AllocationError, "Failed to create map" if @ptr.null?
|
|
18
|
+
|
|
19
|
+
HarfBuzz::Map.define_finalizer(self, @ptr)
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Returns the singleton empty map
|
|
23
|
+
# @return [Map]
|
|
24
|
+
def self.empty
|
|
25
|
+
wrap_borrowed(C.hb_map_get_empty)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# @return [Integer] Number of entries
|
|
29
|
+
def size
|
|
30
|
+
C.hb_map_get_population(@ptr)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
alias length size
|
|
34
|
+
|
|
35
|
+
# @return [Boolean] true if empty
|
|
36
|
+
def empty?
|
|
37
|
+
C.from_hb_bool(C.hb_map_is_empty(@ptr))
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# @param key [Integer] Key
|
|
41
|
+
# @return [Boolean] true if key exists
|
|
42
|
+
def has_key?(key)
|
|
43
|
+
C.from_hb_bool(C.hb_map_has(@ptr, key))
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
alias include? has_key?
|
|
47
|
+
alias key? has_key?
|
|
48
|
+
|
|
49
|
+
# @param key [Integer] Key
|
|
50
|
+
# @return [Integer] Value (HB_MAP_VALUE_INVALID if not found)
|
|
51
|
+
def [](key)
|
|
52
|
+
val = C.hb_map_get(@ptr, key)
|
|
53
|
+
val == HB_MAP_VALUE_INVALID ? nil : val
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
# @param key [Integer] Key
|
|
57
|
+
# @param value [Integer] Value
|
|
58
|
+
def []=(key, value)
|
|
59
|
+
C.hb_map_set(@ptr, key, value)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
# Deletes a key
|
|
63
|
+
# @param key [Integer] Key to delete
|
|
64
|
+
def delete(key)
|
|
65
|
+
C.hb_map_del(@ptr, key)
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Clears all entries
|
|
69
|
+
# @return [self]
|
|
70
|
+
def clear
|
|
71
|
+
C.hb_map_clear(@ptr)
|
|
72
|
+
self
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# @param other [Map] Map to compare
|
|
76
|
+
# @return [Boolean] true if equal
|
|
77
|
+
def ==(other)
|
|
78
|
+
return false unless other.is_a?(Map)
|
|
79
|
+
|
|
80
|
+
C.from_hb_bool(C.hb_map_is_equal(@ptr, other.ptr))
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# @return [Integer] Hash of this map
|
|
84
|
+
def hash
|
|
85
|
+
C.hb_map_hash(@ptr)
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# Copies entries from another map into this one
|
|
89
|
+
# @param other [Map] Source map
|
|
90
|
+
# @return [self]
|
|
91
|
+
def update(other)
|
|
92
|
+
C.hb_map_update(@ptr, other.ptr)
|
|
93
|
+
self
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
alias merge! update
|
|
97
|
+
|
|
98
|
+
# @return [Boolean] true if the last allocation was successful
|
|
99
|
+
def allocation_successful?
|
|
100
|
+
C.from_hb_bool(C.hb_map_allocation_successful(@ptr))
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# @return [Set] Set of all keys
|
|
104
|
+
def keys
|
|
105
|
+
set = Set.new
|
|
106
|
+
C.hb_map_keys(@ptr, set.ptr)
|
|
107
|
+
set
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# @return [Set] Set of all values
|
|
111
|
+
def values
|
|
112
|
+
set = Set.new
|
|
113
|
+
C.hb_map_values(@ptr, set.ptr)
|
|
114
|
+
set
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# Iterates over key-value pairs
|
|
118
|
+
# @yield [key, value]
|
|
119
|
+
# @return [Enumerator] if no block given
|
|
120
|
+
def each
|
|
121
|
+
return to_enum(:each) unless block_given?
|
|
122
|
+
|
|
123
|
+
idx_ptr = FFI::MemoryPointer.new(:int)
|
|
124
|
+
idx_ptr.write_int(-1)
|
|
125
|
+
key_ptr = FFI::MemoryPointer.new(:uint32)
|
|
126
|
+
val_ptr = FFI::MemoryPointer.new(:uint32)
|
|
127
|
+
|
|
128
|
+
while C.from_hb_bool(C.hb_map_next(@ptr, idx_ptr, key_ptr, val_ptr))
|
|
129
|
+
yield key_ptr.read_uint32, val_ptr.read_uint32
|
|
130
|
+
end
|
|
131
|
+
self
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
def inspect
|
|
135
|
+
"#<HarfBuzz::Map size=#{size}>"
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def self.wrap_owned(ptr)
|
|
139
|
+
obj = allocate
|
|
140
|
+
obj.instance_variable_set(:@ptr, ptr)
|
|
141
|
+
define_finalizer(obj, ptr)
|
|
142
|
+
obj
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def self.wrap_borrowed(ptr)
|
|
146
|
+
obj = allocate
|
|
147
|
+
obj.instance_variable_set(:@ptr, ptr)
|
|
148
|
+
obj.instance_variable_set(:@borrowed, true)
|
|
149
|
+
obj
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
def self.define_finalizer(obj, ptr)
|
|
153
|
+
destroy = C.method(:hb_map_destroy)
|
|
154
|
+
ObjectSpace.define_finalizer(obj, proc { destroy.call(ptr) })
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
end
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module HarfBuzz
|
|
4
|
+
module OT
|
|
5
|
+
# OpenType Color Fonts API (CPAL, COLR, SVG, CBDT/CBLC)
|
|
6
|
+
module Color
|
|
7
|
+
module_function
|
|
8
|
+
|
|
9
|
+
# @param face [Face] Font face
|
|
10
|
+
# @return [Boolean] true if the face has CPAL color palettes
|
|
11
|
+
def has_palettes?(face)
|
|
12
|
+
C.from_hb_bool(C.hb_ot_color_has_palettes(face.ptr))
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# @param face [Face] Font face
|
|
16
|
+
# @return [Integer] Number of palettes
|
|
17
|
+
def palette_count(face)
|
|
18
|
+
C.hb_ot_color_palette_get_count(face.ptr)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
# @param face [Face] Font face
|
|
22
|
+
# @param idx [Integer] Palette index
|
|
23
|
+
# @return [Integer] Name ID
|
|
24
|
+
def palette_name_id(face, idx)
|
|
25
|
+
C.hb_ot_color_palette_get_name_id(face.ptr, idx)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# @param face [Face] Font face
|
|
29
|
+
# @param idx [Integer] Color index within palette
|
|
30
|
+
# @return [Integer] Name ID
|
|
31
|
+
def palette_color_name_id(face, idx)
|
|
32
|
+
C.hb_ot_color_palette_color_get_name_id(face.ptr, idx)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# @param face [Face] Font face
|
|
36
|
+
# @param idx [Integer] Palette index
|
|
37
|
+
# @return [Integer] Palette flags bitmask
|
|
38
|
+
def palette_flags(face, idx)
|
|
39
|
+
C.hb_ot_color_palette_get_flags(face.ptr, idx)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Returns colors in a palette
|
|
43
|
+
# @param face [Face] Font face
|
|
44
|
+
# @param idx [Integer] Palette index
|
|
45
|
+
# @return [Array<Integer>] Array of RGBA color values
|
|
46
|
+
def palette_colors(face, idx)
|
|
47
|
+
count_ptr = FFI::MemoryPointer.new(:uint)
|
|
48
|
+
count_ptr.write_uint(0)
|
|
49
|
+
C.hb_ot_color_palette_get_colors(face.ptr, idx, 0, count_ptr, nil)
|
|
50
|
+
count = count_ptr.read_uint
|
|
51
|
+
return [] if count.zero?
|
|
52
|
+
|
|
53
|
+
colors_ptr = FFI::MemoryPointer.new(:uint32, count)
|
|
54
|
+
count_ptr.write_uint(count)
|
|
55
|
+
C.hb_ot_color_palette_get_colors(face.ptr, idx, 0, count_ptr, colors_ptr)
|
|
56
|
+
colors_ptr.read_array_of_uint32(count_ptr.read_uint)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# @param face [Face] Font face
|
|
60
|
+
# @return [Boolean] true if face has COLR layers
|
|
61
|
+
def has_layers?(face)
|
|
62
|
+
C.from_hb_bool(C.hb_ot_color_has_layers(face.ptr))
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# Returns COLR layers for a glyph
|
|
66
|
+
# @param face [Face] Font face
|
|
67
|
+
# @param glyph [Integer] Glyph ID
|
|
68
|
+
# @return [Array<C::HbOtColorLayerT>] Layer array
|
|
69
|
+
def glyph_layers(face, glyph)
|
|
70
|
+
count_ptr = FFI::MemoryPointer.new(:uint)
|
|
71
|
+
count_ptr.write_uint(0)
|
|
72
|
+
C.hb_ot_color_glyph_get_layers(face.ptr, glyph, 0, count_ptr, nil)
|
|
73
|
+
count = count_ptr.read_uint
|
|
74
|
+
return [] if count.zero?
|
|
75
|
+
|
|
76
|
+
layers_ptr = FFI::MemoryPointer.new(C::HbOtColorLayerT, count)
|
|
77
|
+
count_ptr.write_uint(count)
|
|
78
|
+
C.hb_ot_color_glyph_get_layers(face.ptr, glyph, 0, count_ptr, layers_ptr)
|
|
79
|
+
actual = count_ptr.read_uint
|
|
80
|
+
actual.times.map { |i| C::HbOtColorLayerT.new(layers_ptr + i * C::HbOtColorLayerT.size) }
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# @param face [Face] Font face
|
|
84
|
+
# @return [Boolean] true if face has SVG glyphs
|
|
85
|
+
def has_svg?(face)
|
|
86
|
+
C.from_hb_bool(C.hb_ot_color_has_svg(face.ptr))
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Returns the SVG blob for a glyph
|
|
90
|
+
# @param face [Face] Font face
|
|
91
|
+
# @param glyph [Integer] Glyph ID
|
|
92
|
+
# @return [Blob] SVG data blob
|
|
93
|
+
def glyph_svg(face, glyph)
|
|
94
|
+
Blob.wrap_owned(C.hb_ot_color_glyph_reference_svg(face.ptr, glyph))
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
# @param face [Face] Font face
|
|
98
|
+
# @return [Boolean] true if face has PNG glyphs
|
|
99
|
+
def has_png?(face)
|
|
100
|
+
C.from_hb_bool(C.hb_ot_color_has_png(face.ptr))
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Returns the PNG blob for a glyph at a given size
|
|
104
|
+
# @param font [Font] Sized font
|
|
105
|
+
# @param glyph [Integer] Glyph ID
|
|
106
|
+
# @return [Blob] PNG data blob
|
|
107
|
+
def glyph_png(font, glyph)
|
|
108
|
+
Blob.wrap_owned(C.hb_ot_color_glyph_reference_png(font.ptr, glyph))
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# @param face [Face] Font face
|
|
112
|
+
# @return [Boolean] true if face has COLRv1 paint data
|
|
113
|
+
def has_paint?(face)
|
|
114
|
+
C.from_hb_bool(C.hb_ot_color_has_paint(face.ptr))
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
# @param face [Face] Font face
|
|
118
|
+
# @param glyph [Integer] Glyph ID
|
|
119
|
+
# @return [Boolean] true if glyph has COLRv1 paint data
|
|
120
|
+
def glyph_has_paint?(face, glyph)
|
|
121
|
+
C.from_hb_bool(C.hb_ot_color_glyph_has_paint(face.ptr, glyph))
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end
|
|
125
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module HarfBuzz
|
|
4
|
+
module OT
|
|
5
|
+
# OpenType Font functions
|
|
6
|
+
module Font
|
|
7
|
+
module_function
|
|
8
|
+
|
|
9
|
+
# Sets OpenType font functions on a font
|
|
10
|
+
# @param font [HarfBuzz::Font] Font to configure
|
|
11
|
+
def set_funcs(font)
|
|
12
|
+
C.hb_ot_font_set_funcs(font.ptr)
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|