mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-19 18:26:13 +03:00
fontconfig: fc-match
This commit is contained in:
16
pkg/fontconfig/common.zig
Normal file
16
pkg/fontconfig/common.zig
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const c = @import("c.zig");
|
||||||
|
|
||||||
|
pub const Result = enum(c_uint) {
|
||||||
|
match = c.FcResultMatch,
|
||||||
|
no_match = c.FcResultNoMatch,
|
||||||
|
type_mismatch = c.FcResultTypeMismatch,
|
||||||
|
no_id = c.FcResultNoId,
|
||||||
|
out_of_memory = c.FcResultOutOfMemory,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const MatchKind = enum(c_uint) {
|
||||||
|
pattern = c.FcMatchPattern,
|
||||||
|
font = c.FcMatchFont,
|
||||||
|
scan = c.FcMatchScan,
|
||||||
|
};
|
@ -4,6 +4,8 @@ const CharSet = @import("char_set.zig").CharSet;
|
|||||||
const FontSet = @import("font_set.zig").FontSet;
|
const FontSet = @import("font_set.zig").FontSet;
|
||||||
const ObjectSet = @import("object_set.zig").ObjectSet;
|
const ObjectSet = @import("object_set.zig").ObjectSet;
|
||||||
const Pattern = @import("pattern.zig").Pattern;
|
const Pattern = @import("pattern.zig").Pattern;
|
||||||
|
const Result = @import("main.zig").Result;
|
||||||
|
const MatchKind = @import("main.zig").MatchKind;
|
||||||
|
|
||||||
pub const Config = opaque {
|
pub const Config = opaque {
|
||||||
pub fn destroy(self: *Config) void {
|
pub fn destroy(self: *Config) void {
|
||||||
@ -53,17 +55,3 @@ pub const FontSortResult = struct {
|
|||||||
result: Result,
|
result: Result,
|
||||||
fs: *FontSet,
|
fs: *FontSet,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub const Result = enum(c_uint) {
|
|
||||||
match = c.FcResultMatch,
|
|
||||||
no_match = c.FcResultNoMatch,
|
|
||||||
type_mismatch = c.FcResultTypeMismatch,
|
|
||||||
no_id = c.FcResultNoId,
|
|
||||||
out_of_memory = c.FcResultOutOfMemory,
|
|
||||||
};
|
|
||||||
|
|
||||||
pub const MatchKind = enum(c_uint) {
|
|
||||||
pattern = c.FcMatchPattern,
|
|
||||||
font = c.FcMatchFont,
|
|
||||||
scan = c.FcMatchScan,
|
|
||||||
};
|
|
||||||
|
25
pkg/fontconfig/lang_set.zig
Normal file
25
pkg/fontconfig/lang_set.zig
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const assert = std.debug.assert;
|
||||||
|
const c = @import("c.zig");
|
||||||
|
|
||||||
|
pub const LangSet = opaque {
|
||||||
|
pub fn create() *LangSet {
|
||||||
|
return @ptrCast(*LangSet, c.FcLangSetCreate());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn destroy(self: *LangSet) void {
|
||||||
|
c.FcLangSetDestroy(self.cval());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub inline fn cval(self: *LangSet) *c.struct__FcLangSet {
|
||||||
|
return @ptrCast(
|
||||||
|
*c.struct__FcLangSet,
|
||||||
|
self,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
test "create" {
|
||||||
|
var fs = LangSet.create();
|
||||||
|
defer fs.destroy();
|
||||||
|
}
|
@ -1,10 +1,15 @@
|
|||||||
pub const c = @import("c.zig");
|
pub const c = @import("c.zig");
|
||||||
pub usingnamespace @import("init.zig");
|
pub usingnamespace @import("init.zig");
|
||||||
pub usingnamespace @import("char_set.zig");
|
pub usingnamespace @import("char_set.zig");
|
||||||
|
pub usingnamespace @import("common.zig");
|
||||||
pub usingnamespace @import("config.zig");
|
pub usingnamespace @import("config.zig");
|
||||||
pub usingnamespace @import("font_set.zig");
|
pub usingnamespace @import("font_set.zig");
|
||||||
|
pub usingnamespace @import("lang_set.zig");
|
||||||
|
pub usingnamespace @import("matrix.zig");
|
||||||
pub usingnamespace @import("object_set.zig");
|
pub usingnamespace @import("object_set.zig");
|
||||||
pub usingnamespace @import("pattern.zig");
|
pub usingnamespace @import("pattern.zig");
|
||||||
|
pub usingnamespace @import("range.zig");
|
||||||
|
pub usingnamespace @import("value.zig");
|
||||||
|
|
||||||
test {
|
test {
|
||||||
@import("std").testing.refAllDecls(@This());
|
@import("std").testing.refAllDecls(@This());
|
||||||
|
10
pkg/fontconfig/matrix.zig
Normal file
10
pkg/fontconfig/matrix.zig
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const assert = std.debug.assert;
|
||||||
|
const c = @import("c.zig");
|
||||||
|
|
||||||
|
pub const Matrix = extern struct {
|
||||||
|
xx: f64,
|
||||||
|
xy: f64,
|
||||||
|
yx: f64,
|
||||||
|
yy: f64,
|
||||||
|
};
|
@ -1,5 +1,9 @@
|
|||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
|
const assert = std.debug.assert;
|
||||||
const c = @import("c.zig");
|
const c = @import("c.zig");
|
||||||
|
const Result = @import("main.zig").Result;
|
||||||
|
const Value = @import("main.zig").Value;
|
||||||
|
const ValueBinding = @import("main.zig").ValueBinding;
|
||||||
|
|
||||||
pub const Pattern = opaque {
|
pub const Pattern = opaque {
|
||||||
pub fn create() *Pattern {
|
pub fn create() *Pattern {
|
||||||
@ -18,6 +22,10 @@ pub const Pattern = opaque {
|
|||||||
c.FcDefaultSubstitute(self.cval());
|
c.FcDefaultSubstitute(self.cval());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn objectIterator(self: *Pattern) ObjectIterator {
|
||||||
|
return .{ .pat = self.cval(), .iter = null };
|
||||||
|
}
|
||||||
|
|
||||||
pub fn print(self: *Pattern) void {
|
pub fn print(self: *Pattern) void {
|
||||||
c.FcPatternPrint(self.cval());
|
c.FcPatternPrint(self.cval());
|
||||||
}
|
}
|
||||||
@ -25,6 +33,85 @@ pub const Pattern = opaque {
|
|||||||
pub inline fn cval(self: *Pattern) *c.struct__FcPattern {
|
pub inline fn cval(self: *Pattern) *c.struct__FcPattern {
|
||||||
return @ptrCast(*c.struct__FcPattern, self);
|
return @ptrCast(*c.struct__FcPattern, self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const ObjectIterator = struct {
|
||||||
|
pat: *c.struct__FcPattern,
|
||||||
|
iter: ?c.struct__FcPatternIter,
|
||||||
|
|
||||||
|
/// Move to the next object, returns true if there is another
|
||||||
|
/// object and false otherwise. If this is the first call, this
|
||||||
|
/// will be teh first object.
|
||||||
|
pub fn next(self: *ObjectIterator) bool {
|
||||||
|
// Null means our first iterator
|
||||||
|
if (self.iter == null) {
|
||||||
|
// If we have no objects, do not create iterator
|
||||||
|
if (c.FcPatternObjectCount(self.pat) == 0) return false;
|
||||||
|
|
||||||
|
var iter: c.struct__FcPatternIter = undefined;
|
||||||
|
c.FcPatternIterStart(
|
||||||
|
self.pat,
|
||||||
|
&iter,
|
||||||
|
);
|
||||||
|
assert(c.FcPatternIterIsValid(self.pat, &iter) == c.FcTrue);
|
||||||
|
self.iter = iter;
|
||||||
|
|
||||||
|
// Return right away because the fontconfig iterator pattern
|
||||||
|
// is do/while.
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.FcPatternIterNext(
|
||||||
|
self.pat,
|
||||||
|
@ptrCast([*c]c.struct__FcPatternIter, &self.iter),
|
||||||
|
) == c.FcTrue;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn object(self: *ObjectIterator) []const u8 {
|
||||||
|
return std.mem.sliceTo(c.FcPatternIterGetObject(
|
||||||
|
self.pat,
|
||||||
|
&self.iter.?,
|
||||||
|
), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn valueLen(self: *ObjectIterator) usize {
|
||||||
|
return @intCast(usize, c.FcPatternIterValueCount(self.pat, &self.iter.?));
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn valueIterator(self: *ObjectIterator) ValueIterator {
|
||||||
|
return .{
|
||||||
|
.pat = self.pat,
|
||||||
|
.iter = &self.iter.?,
|
||||||
|
.max = c.FcPatternIterValueCount(self.pat, &self.iter.?),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const ValueIterator = struct {
|
||||||
|
pat: *c.struct__FcPattern,
|
||||||
|
iter: *c.struct__FcPatternIter,
|
||||||
|
max: c_int,
|
||||||
|
id: c_int = 0,
|
||||||
|
|
||||||
|
pub const Entry = struct {
|
||||||
|
result: Result,
|
||||||
|
value: Value,
|
||||||
|
binding: ValueBinding,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub fn next(self: *ValueIterator) ?Entry {
|
||||||
|
if (self.id >= self.max) return null;
|
||||||
|
var value: c.struct__FcValue = undefined;
|
||||||
|
var binding: c.FcValueBinding = undefined;
|
||||||
|
const result = c.FcPatternIterGetValue(self.pat, self.iter, self.id, &value, &binding);
|
||||||
|
self.id += 1;
|
||||||
|
|
||||||
|
return Entry{
|
||||||
|
.result = @intToEnum(Result, result),
|
||||||
|
.binding = @intToEnum(ValueBinding, binding),
|
||||||
|
.value = Value.init(&value),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
test "create" {
|
test "create" {
|
||||||
|
16
pkg/fontconfig/range.zig
Normal file
16
pkg/fontconfig/range.zig
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const assert = std.debug.assert;
|
||||||
|
const c = @import("c.zig");
|
||||||
|
|
||||||
|
pub const Range = opaque {
|
||||||
|
pub fn destroy(self: *Range) void {
|
||||||
|
c.FcRangeDestroy(self.cval());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub inline fn cval(self: *Range) *c.struct__FcRange {
|
||||||
|
return @ptrCast(
|
||||||
|
*c.struct__FcRange,
|
||||||
|
self,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
};
|
@ -50,5 +50,17 @@ test "fc-match" {
|
|||||||
pat.destroy();
|
pat.destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
{}
|
{
|
||||||
|
for (fs.fonts()) |font| {
|
||||||
|
var it = font.objectIterator();
|
||||||
|
while (it.next()) {
|
||||||
|
try testing.expect(it.object().len > 0);
|
||||||
|
try testing.expect(it.valueLen() > 0);
|
||||||
|
var value_it = it.valueIterator();
|
||||||
|
while (value_it.next()) |entry| {
|
||||||
|
try testing.expect(entry.value != .unknown);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
57
pkg/fontconfig/value.zig
Normal file
57
pkg/fontconfig/value.zig
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
const std = @import("std");
|
||||||
|
const assert = std.debug.assert;
|
||||||
|
const c = @import("c.zig");
|
||||||
|
const CharSet = @import("main.zig").CharSet;
|
||||||
|
const LangSet = @import("main.zig").LangSet;
|
||||||
|
const Matrix = @import("main.zig").Matrix;
|
||||||
|
const Range = @import("main.zig").Range;
|
||||||
|
|
||||||
|
pub const Type = enum(c_int) {
|
||||||
|
unknown = c.FcTypeUnknown,
|
||||||
|
@"void" = c.FcTypeVoid,
|
||||||
|
integer = c.FcTypeInteger,
|
||||||
|
double = c.FcTypeDouble,
|
||||||
|
string = c.FcTypeString,
|
||||||
|
@"bool" = c.FcTypeBool,
|
||||||
|
matrix = c.FcTypeMatrix,
|
||||||
|
char_set = c.FcTypeCharSet,
|
||||||
|
ft_face = c.FcTypeFTFace,
|
||||||
|
lang_set = c.FcTypeLangSet,
|
||||||
|
range = c.FcTypeRange,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const Value = union(Type) {
|
||||||
|
unknown: void,
|
||||||
|
@"void": void,
|
||||||
|
integer: u32,
|
||||||
|
double: f64,
|
||||||
|
string: []const u8,
|
||||||
|
@"bool": bool,
|
||||||
|
matrix: *const Matrix,
|
||||||
|
char_set: *const CharSet,
|
||||||
|
ft_face: *anyopaque,
|
||||||
|
lang_set: *const LangSet,
|
||||||
|
range: *const Range,
|
||||||
|
|
||||||
|
pub fn init(cvalue: *c.struct__FcValue) Value {
|
||||||
|
return switch (@intToEnum(Type, cvalue.@"type")) {
|
||||||
|
.unknown => .{ .unknown = {} },
|
||||||
|
.@"void" => .{ .@"void" = {} },
|
||||||
|
.string => .{ .string = std.mem.sliceTo(cvalue.u.s, 0) },
|
||||||
|
.integer => .{ .integer = @intCast(u32, cvalue.u.i) },
|
||||||
|
.double => .{ .double = cvalue.u.d },
|
||||||
|
.@"bool" => .{ .@"bool" = cvalue.u.b == c.FcTrue },
|
||||||
|
.matrix => .{ .matrix = @ptrCast(*const Matrix, cvalue.u.m) },
|
||||||
|
.char_set => .{ .char_set = @ptrCast(*const CharSet, cvalue.u.c) },
|
||||||
|
.ft_face => .{ .ft_face = @ptrCast(*anyopaque, cvalue.u.f) },
|
||||||
|
.lang_set => .{ .lang_set = @ptrCast(*const LangSet, cvalue.u.l) },
|
||||||
|
.range => .{ .range = @ptrCast(*const Range, cvalue.u.r) },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
pub const ValueBinding = enum(c_int) {
|
||||||
|
weak = c.FcValueBindingWeak,
|
||||||
|
strong = c.FcValueBindingStrong,
|
||||||
|
same = c.FcValueBindingSame,
|
||||||
|
};
|
Reference in New Issue
Block a user