Skip to documentation
SLOP

tiny.filigree.font.description

Reference tiny.filigree font description

Defined in font.

API (5)

Actions

Public operations.

Types and contracts

Public types and contracts.

Values and defaults

Public values and defaults.

No direct callersNo direct callsfontdescription
Static calls · unresolved targets: unknown · external targets: unknown.

Source

Source: lib/filigree/src/font/description.zig

zig
const std = @import("std");const binary = @import("binary.zig");const directory = @import("directory.zig");const model = @import("model.zig");const names = @import("names.zig");const cmap_owner = @import("cmap.zig");/// Coverage beyond the four OS/2 Unicode-range words.pub const extended_emoji_word: usize = 4;pub const extended_emoji_bit: u5 = 0;pub const Description = struct {    family: []u8,    weight_class: u16,    width_class: u16,    selection: u16,    units_per_em: u16,    ascent: f32,    descent: f32,    line_gap: f32,    coverage: [8]u32,    fixed_pitch: bool,    color: bool,    face_index: u32,    pub fn deinit(self: *Description, allocator: std.mem.Allocator) void {        allocator.free(self.family);        self.* = undefined;    }};pub fn describeAlloc(allocator: std.mem.Allocator, data: []const u8) (model.FontError || error{OutOfMemory})!Description {    return describeAtAlloc(allocator, data, 0);}pub fn describeAtAlloc(allocator: std.mem.Allocator, data: []const u8, face_index: u32) (model.FontError || error{OutOfMemory})!Description {    const offset = try directory.fontDirectoryOffset(data, face_index);    const os2 = try directory.tableAt(data, offset, "OS/2");    if (os2.len < 64) return error.InvalidFont;    const head = try directory.tableAt(data, offset, "head");    const hhea = try directory.tableAt(data, offset, "hhea");    if (head.len < 54 or hhea.len < 10) return error.InvalidFont;    const units_per_em = try binary.readU16(data, head.offset + 18);    if (units_per_em == 0) return error.InvalidFont;    const selection = try binary.readU16(data, os2.offset + 62);    const metric_source = if (selection & 0x80 != 0) os2 else hhea;    if (selection & 0x80 != 0 and os2.len < 78) return error.InvalidFont;    const metric_offset: usize = if (selection & 0x80 != 0) 68 else 4;    const scale = @as(f32, @floatFromInt(units_per_em));    const cmap_table = try directory.tableAt(data, offset, "cmap");    const cmap = try cmap_owner.Cmap.init(data, cmap_table);    var coverage: [8]u32 = @splat(0);    inline for (0..4) |word| {        coverage[word] = try binary.readU32(data, os2.offset + 42 + word * 4);    }    if (try hasEmoji(data, cmap)) coverage[extended_emoji_word] |= @as(u32, 1) << extended_emoji_bit;    const post = directory.tableAt(data, offset, "post") catch |err| switch (err) {        error.MissingTable => null,        else => return err,    };    const name_table = try directory.tableAt(data, offset, "name");    const record = (try names.bestNameRecord(data, name_table, 16)) orelse        (try names.bestNameRecord(data, name_table, 1)) orelse return error.InvalidFont;    const family = names.utf16BeToUtf8Alloc(allocator, record.bytes) catch |err| switch (err) {        error.OutOfMemory => return error.OutOfMemory,        else => return error.InvalidFont,    };    errdefer allocator.free(family);    return .{        .family = family,        .weight_class = try binary.readU16(data, os2.offset + 4),        .width_class = try binary.readU16(data, os2.offset + 6),        .selection = selection,        .units_per_em = units_per_em,        .ascent = @as(f32, @floatFromInt(try binary.readI16(data, metric_source.offset + metric_offset))) / scale,        .descent = @as(f32, @floatFromInt(try binary.readI16(data, metric_source.offset + metric_offset + 2))) / scale,        .line_gap = @as(f32, @floatFromInt(try binary.readI16(data, metric_source.offset + metric_offset + 4))) / scale,        .coverage = coverage,        .fixed_pitch = if (post) |table| try readFixedPitch(data, table) else false,        .color = directory.optionalAt(data, offset, "COLR") != null or            directory.optionalAt(data, offset, "CBDT") != null or            directory.optionalAt(data, offset, "sbix") != null or            directory.optionalAt(data, offset, "SVG ") != null,        .face_index = face_index,    };}fn hasEmoji(data: []const u8, cmap: cmap_owner.Cmap) model.FontError!bool {    for (0x1f300..0x1fb00) |codepoint| {        if (try cmap.map(data, @intCast(codepoint)) != 0) return true;    }    return false;}fn readFixedPitch(data: []const u8, table: binary.Table) model.FontError!bool {    if (table.len < 16) return error.InvalidFont;    return (try binary.readU32(data, table.offset + 12)) != 0;}test "face description reads family and OS/2 fields" {    const fixture = @import("../fixture/root.zig");    const allocator = std.testing.allocator;    const bytes = try fixture.createWithMetricVariations(allocator);    defer allocator.free(bytes);    const os2 = try directory.table(bytes, "OS/2");    std.mem.writeInt(u16, bytes[os2.offset + 4 ..][0..2], 700, .big);    std.mem.writeInt(u16, bytes[os2.offset + 6 ..][0..2], 3, .big);    std.mem.writeInt(u32, bytes[os2.offset + 42 ..][0..4], 0x201, .big);    std.mem.writeInt(u16, bytes[os2.offset + 62 ..][0..2], 0x21, .big);    var result = try describeAlloc(allocator, bytes);    defer result.deinit(allocator);    try std.testing.expectEqualStrings("Tiny Fixture", result.family);    try std.testing.expectEqual(@as(u16, 700), result.weight_class);    try std.testing.expectEqual(@as(u16, 3), result.width_class);    try std.testing.expectEqual(@as(u16, 0x21), result.selection);    try std.testing.expectEqual(@as(u32, 0x201), result.coverage[0]);    try std.testing.expectEqual(@as(u16, 1000), result.units_per_em);    try std.testing.expectEqual(@as(f32, 0.8), result.ascent);    try std.testing.expectEqual(@as(f32, -0.2), result.descent);    try std.testing.expectEqual(@as(f32, 0), result.line_gap);    try std.testing.expect(!result.fixed_pitch);    try std.testing.expect(!result.color);    try std.testing.expectEqual(@as(u32, 0), result.face_index);}test "face description selects OS/2 typo metrics when requested" {    const fixture = @import("../fixture/root.zig");    const allocator = std.testing.allocator;    const bytes = try fixture.createWithMetricVariations(allocator);    defer allocator.free(bytes);    var result = try describeAlloc(allocator, bytes);    defer result.deinit(allocator);    try std.testing.expectEqual(@as(f32, 0.8), result.ascent);    try std.testing.expectEqual(@as(f32, -0.2), result.descent);    try std.testing.expectEqual(@as(f32, 0.04), result.line_gap);}test "face description derives extended emoji coverage from cmap" {    var bytes: [40]u8 = @splat(0);    std.mem.writeInt(u16, bytes[2..4], 1, .big);    std.mem.writeInt(u16, bytes[4..6], 3, .big);    std.mem.writeInt(u16, bytes[6..8], 10, .big);    std.mem.writeInt(u32, bytes[8..12], 12, .big);    std.mem.writeInt(u16, bytes[12..14], 12, .big);    std.mem.writeInt(u32, bytes[16..20], 28, .big);    std.mem.writeInt(u32, bytes[24..28], 1, .big);    std.mem.writeInt(u32, bytes[28..32], 0x1f600, .big);    std.mem.writeInt(u32, bytes[32..36], 0x1f600, .big);    std.mem.writeInt(u32, bytes[36..40], 1, .big);    const cmap = try cmap_owner.Cmap.init(&bytes, .{ .offset = 0, .len = bytes.len });    try std.testing.expect(try hasEmoji(&bytes, cmap));}test "face description reads post fixed pitch and rejects a short table" {    var bytes: [16]u8 = @splat(0);    std.mem.writeInt(u32, bytes[12..16], 1, .big);    try std.testing.expect(try readFixedPitch(&bytes, .{ .offset = 0, .len = bytes.len }));    try std.testing.expectError(error.InvalidFont, readFixedPitch(&bytes, .{ .offset = 0, .len = 15 }));}test "face description rejects missing and truncated OS/2" {    const fixture = @import("../fixture/root.zig");    const allocator = std.testing.allocator;    const missing = try fixture.create(allocator);    defer allocator.free(missing);    try std.testing.expectError(error.MissingTable, describeAlloc(allocator, missing));    const bytes = try fixture.createWithMetricVariations(allocator);    defer allocator.free(bytes);    const os2 = try directory.table(bytes, "OS/2");    const records = try binary.readU16(bytes, 4);    for (0..records) |index| {        const row = 12 + index * 16;        if (try binary.readU32(bytes, row) != model.tag("OS/2")) continue;        std.mem.writeInt(u32, bytes[row + 12 ..][0..4], 63, .big);        break;    }    _ = os2;    try std.testing.expectError(error.InvalidFont, describeAlloc(allocator, bytes));}

Source: lib/filigree/src/font/root.zig:5

zig
pub const description = @import("description.zig");

Audit

Definitions3
Public names3
Members0
Version26.7.0
Revisiondaab053ee433