Something went wrong. Try again.
A Zig library that finds fonts as fontconfig does, without it: the same configuration, OpenType and bitmap fonts, and the same answers.
Something went wrong. Try again.
4.5 kB · 113 lines
Zig
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114// SPDX-FileCopyrightText: © 2026 Jeffrey C. Ollie <jeff@ocjtech.us>// SPDX-FileCopyrightText: © 2001 Keith Packard// SPDX-License-Identifier: MIT AND HPND-sell-variant
//! `FcConfigSetDefaultSubstitute`, from `fcdefault.c`: what a query that//! does not say otherwise is taken to want.
const std = @import("std");const Allocator = std.mem.Allocator;const object = @import("object.zig");const Pattern = @import("Pattern.zig");const Builtin = object.Builtin;
pub const Defaults = struct { /// The first of the default languages. default_lang: []const u8, prgname: ?[]const u8 = null, desktop: ?[]const u8 = null,};
const bool_defaults = [_]struct { Builtin, bool }{ .{ .hinting, true }, .{ .verticallayout, false }, .{ .autohint, false }, .{ .globaladvance, true }, .{ .embeddedbitmap, true }, .{ .decorative, false }, .{ .symbol, false }, .{ .variable, false },};
pub fn substitute(p: *Pattern, d: Defaults) Allocator.Error!void { if (p.findBuiltin(.weight) == null) try p.addInteger(.weight, object.weight.regular); if (p.findBuiltin(.slant) == null) try p.addInteger(.slant, object.slant.roman); if (p.findBuiltin(.width) == null) try p.addInteger(.width, object.width.normal); for (bool_defaults) |b| { if (p.findBuiltin(b[0]) == null) try p.addBool(b[0], b[1]); }
// The size: a double, or the middle of a range, or 12. var size: f64 = 12; if (p.getDouble(.size, 0)) |s| { size = s; } else if (p.getBuiltin(.size, 0)) |v| switch (v) { .range => |r| size = (r.begin + r.end) * 0.5, else => {}, }; const scale = p.getDouble(.scale, 0) orelse 1.0; const dpi = p.getDouble(.dpi, 0) orelse 75.0;
// A pixel size is computed from the size, or the size from a pixel // size given instead. if (p.findBuiltin(.pixelsize)) |e| { const v = e.values.?.value; const px: f64 = switch (v) { .integer => |i| @floatFromInt(i), .double => |x| x, else => 0, }; size = px / dpi * 72.0 / scale; } else { _ = p.del(.{ .builtin = .scale }); try p.addDouble(.scale, scale); _ = p.del(.{ .builtin = .dpi }); try p.addDouble(.dpi, dpi); try p.addDouble(.pixelsize, size * scale * (dpi / 72.0)); } _ = p.del(.{ .builtin = .size }); try p.addDouble(.size, size);
if (p.findBuiltin(.fontversion) == null) try p.addInteger(.fontversion, 0x7fffffff); if (p.findBuiltin(.hintstyle) == null) try p.addInteger(.hintstyle, object.hint.full); if (p.findBuiltin(.namelang) == null) try p.addString(.namelang, d.default_lang);
// A name in the requested language, or failing that in English: en-us, // weakly, rather than en, so that an exact match on a language with a // territory still scores better. const namelang = p.getBuiltin(.namelang, 0).?; for ([_]Builtin{ .familylang, .stylelang, .fullnamelang }) |b| { if (p.findBuiltin(b) == null) { _ = try p.addBorrowed(.{ .builtin = b }, namelang, .strong, true); _ = try p.addWithBinding(.{ .builtin = b }, .{ .string = "en-us" }, .weak, true); } }
if (p.findBuiltin(.prgname) == null) { if (d.prgname) |n| try p.addString(.prgname, n); } if (p.findBuiltin(.desktop) == null) { if (d.desktop) |n| try p.addString(.desktop, n); } if (p.findBuiltin(.order) == null) try p.addInteger(.order, 0);}
const testing = std.testing;
test "defaults" { var p = try @import("name.zig").parse(testing.allocator, "sans-14:bold"); defer p.deinit(); try substitute(&p, .{ .default_lang = "en" }); try testing.expectEqual(@as(?i32, 200), p.getInteger(.weight, 0)); try testing.expectEqual(@as(?i32, 0), p.getInteger(.slant, 0)); try testing.expectEqual(@as(?f64, 14), p.getDouble(.size, 0)); try testing.expectApproxEqAbs(@as(f64, 14.0 * 75.0 / 72.0), p.getDouble(.pixelsize, 0).?, 1e-9); try testing.expectEqualStrings("en", p.getString(.familylang, 0).?); try testing.expectEqualStrings("en-us", p.getString(.familylang, 1).?); try testing.expectEqual(Pattern.Binding.weak, p.getList(.{ .builtin = .familylang }, 1).?.binding);
var q = try @import("name.zig").parse(testing.allocator, "sans:pixelsize=20"); defer q.deinit(); try substitute(&q, .{ .default_lang = "en" }); try testing.expectApproxEqAbs(@as(f64, 20.0 / 75.0 * 72.0), q.getDouble(.size, 0).?, 1e-9);}