-
Notifications
You must be signed in to change notification settings - Fork 1
/
blob.zig
126 lines (112 loc) · 4.29 KB
/
blob.zig
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
const std = @import("std");
const c = @import("c.zig").c;
const Error = @import("errors.zig").Error;
/// Data type holding the memory modes available to client programs.
///
/// Regarding these various memory-modes:
///
/// - In no case shall the HarfBuzz client modify memory that is passed to
/// HarfBuzz in a blob. If there is any such possibility,
/// HB_MEMORY_MODE_DUPLICATE should be used such that HarfBuzz makes a
/// copy immediately,
///
/// - Use HB_MEMORY_MODE_READONLY otherwise, unless you really really really
/// know what you are doing,
///
/// - HB_MEMORY_MODE_WRITABLE is appropriate if you really made a copy of
/// data solely for the purpose of passing to HarfBuzz and doing that
/// just once (no reuse!),
///
/// - If the font is mmap()ed, it's okay to use
/// HB_MEMORY_READONLY_MAY_MAKE_WRITABLE , however, using that mode
/// correctly is very tricky. Use HB_MEMORY_MODE_READONLY instead.
pub const MemoryMode = enum(u2) {
/// HarfBuzz immediately makes a copy of the data.
duplicate = c.HB_MEMORY_MODE_DUPLICATE,
/// HarfBuzz client will never modify the data, and HarfBuzz will never
/// modify the data.
readonly = c.HB_MEMORY_MODE_READONLY,
/// HarfBuzz client made a copy of the data solely for HarfBuzz, so
/// HarfBuzz may modify the data.
writable = c.HB_MEMORY_MODE_WRITABLE,
/// See above
readonly_may_make_writable = c.HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE,
};
/// Blobs wrap a chunk of binary data to handle lifecycle management of data
/// while it is passed between client and HarfBuzz. Blobs are primarily
/// used to create font faces, but also to access font face tables, as well as
/// pass around other binary data.
pub const Blob = struct {
handle: *c.hb_blob_t,
/// Creates a new "blob" object wrapping data . The mode parameter is used
/// to negotiate ownership and lifecycle of data .
///
/// Note that this function returns a freshly-allocated empty blob even
/// if length is zero. This is in contrast to hb_blob_create(), which
/// returns the singleton empty blob (as returned by hb_blob_get_empty())
/// if length is zero.
pub fn create(data: []const u8, mode: MemoryMode) Error!Blob {
const handle = c.hb_blob_create_or_fail(
data.ptr,
@intCast(data.len),
@intFromEnum(mode),
null,
null,
) orelse return Error.HarfbuzzFailed;
return Blob{ .handle = handle };
}
/// Decreases the reference count on blob , and if it reaches zero,
/// destroys blob , freeing all memory, possibly calling the
/// destroy-callback the blob was created for if it has not been
/// called already.
pub fn destroy(self: *Blob) void {
c.hb_blob_destroy(self.handle);
}
/// Attaches a user-data key/data pair to the specified blob.
pub fn setUserData(
self: Blob,
comptime T: type,
key: ?*anyopaque,
ptr: ?*T,
comptime destroycb: ?*const fn (?*T) callconv(.C) void,
replace: bool,
) bool {
const Callback = struct {
pub fn callback(data: ?*anyopaque) callconv(.C) void {
@call(.{ .modifier = .always_inline }, destroycb, .{
@as(?*T, @ptrCast(@alignCast(data))),
});
}
};
return c.hb_blob_set_user_data(
self.handle,
@ptrCast(key),
ptr,
if (destroycb != null) Callback.callback else null,
if (replace) 1 else 0,
) > 0;
}
/// Fetches the user data associated with the specified key, attached to
/// the specified font-functions structure.
pub fn getUserData(
self: Blob,
comptime T: type,
key: ?*anyopaque,
) ?*T {
const opt = c.hb_blob_get_user_data(self.handle, @ptrCast(key));
if (opt) |ptr|
return @ptrCast(@alignCast(ptr))
else
return null;
}
};
test {
const testing = std.testing;
const data = "hello";
var blob = try Blob.create(data, .readonly);
defer blob.destroy();
var userdata: u8 = 127;
var key: u8 = 0;
try testing.expect(blob.setUserData(u8, &key, &userdata, null, false));
try testing.expect(blob.getUserData(u8, &key).?.* == 127);
}