tiny.ui.asset
Defined in tiny.ui.
API (31)
Actions
Public operations.
Bytes.sliceCapacity.derivecoverageBitcoverageForScripts: The first four words use OS/2 Unicode-range positions.openWithEmbedded: Returns a ready registry with both embedded faces already registered.primaryFontresolveAuthoredresolveFontscriptFallbacks: Orders faces outside an authored chain for one itemized script run.scriptsFromRuns
Types and contracts
Public types and contracts.
AssetHandleBytesCapacityCapacityErrorCoverageEmbeddedErrorFontFontAuthoredFontDescriptorFontPrimaryFontRequestFontResolutionImageImageDescriptorKindLimitsRegistry
Values and defaults
Public values and defaults.
Source
Source: lib/ui/src/asset/capacity.zig:15
pub const Capacity = struct { total_bytes: usize, font_bytes: usize, image_bytes: usize, string_bytes: usize, owned_bytes: usize, pub fn derive(limits: Limits) Error!Capacity { if (limits.fonts > std.math.maxInt(u32) / family_bytes_per_font) return error.CapacityOverflow; const FontDescriptor = model.FontDescriptor; const ImageDescriptor = model.ImageDescriptor; const Bytes = model.Bytes; const font_count: usize = limits.fonts; const image_count: usize = limits.images; var cursor: usize = 0; try addSlice(&cursor, FontDescriptor, font_count); try addSlice(&cursor, Bytes, font_count); try addSlice(&cursor, u32, font_count); try addSlice(&cursor, u64, std.math.divCeil(usize, font_count, 64) catch unreachable); try addSlice(&cursor, ImageDescriptor, image_count); try addSlice(&cursor, Bytes, image_count); try addSlice(&cursor, u32, image_count); try addSlice(&cursor, u64, std.math.divCeil(usize, image_count, 64) catch unreachable); const string_bytes = std.math.mul(usize, font_count, family_bytes_per_font) catch return error.CapacityOverflow; try addSlice(&cursor, u8, string_bytes); try addSlice(&cursor, u8, limits.owned_bytes); return .{ .total_bytes = cursor, .font_bytes = std.math.mul(usize, font_count, @sizeOf(FontDescriptor)) catch unreachable, .image_bytes = std.math.mul(usize, image_count, @sizeOf(ImageDescriptor)) catch unreachable, .string_bytes = string_bytes, .owned_bytes = limits.owned_bytes, }; }};Source: lib/ui/src/asset/capacity.zig:13
pub const Error = error{CapacityOverflow};Source: lib/ui/src/asset/capacity.zig:7
pub const Limits = struct { fonts: u32 = 32, images: u32 = 16, owned_bytes: u32 = 41_328,};Source: lib/ui/src/asset/model.zig:31
pub const Bytes = union(enum) { borrowed: []const u8, owned: []const u8, pub fn slice(self: Bytes) []const u8 { return switch (self) { .borrowed => |value| value, .owned => |value| value, }; }};Source: lib/ui/src/asset/model.zig:45
pub const Error = error{ FontCapacityExceeded, ImageCapacityExceeded, OwnedBytesExceeded, FamilyTooLong, StaleAsset, GenerationExhausted,};Source: lib/ui/src/asset/model.zig:54
pub const Font = struct { descriptor: FontDescriptor, family: []const u8, bytes: []const u8,};Source: lib/ui/src/asset/model.zig:6
pub const FontDescriptor = extern struct { family_offset: u32 = 0, family_len: u32 = 0, units_per_em: u16 = 1000, weight: u16 = 400, width: u8 = 5, slant: u8 = 0, monospace: u8 = 0, color: u8 = 0, ascent: f32 = 0, descent: f32 = 0, line_gap: f32 = 0, coverage: [8]u32 = @splat(0), face_index: u32 = 0,};Source: lib/ui/src/asset/model.zig:60
pub const Image = struct { descriptor: ImageDescriptor, bytes: []const u8,};Source: lib/ui/src/asset/model.zig:22
pub const ImageDescriptor = extern struct { width: u32 = 0, height: u32 = 0, format: u16 = 0, flags: u16 = 0, stride: u32 = 0, reserved: u32 = 0,};Source: lib/ui/src/asset/model.zig:43
pub const Kind = enum { font, image };Source: lib/ui/src/asset/resolve.zig:85
pub const Authored = struct { face: ?model.AssetHandle, synthetic_slant: bool, fallback: []const model.AssetHandle,};Source: lib/ui/src/asset/resolve.zig:8
pub const Coverage = enum(u6) { latin, cyrillic, cjk, emoji, greek, arabic, hebrew, devanagari, other,};Source: lib/ui/src/asset/resolve.zig:80
pub const Primary = struct { face: ?model.AssetHandle, synthetic_slant: bool,};Source: lib/ui/src/asset/resolve.zig:66
pub const Request = struct { family: []const u8, weight: u16 = 400, slant: u8 = 0, monospace: bool = false, scripts: u64 = 0,};Source: lib/ui/src/asset/resolve.zig:74
pub const Resolution = struct { face: ?model.AssetHandle, synthetic_slant: bool, fallback: []const model.AssetHandle,};Source: lib/ui/src/asset/capacity.zig:5
pub const default_table_bytes: usize = 47_104;Source: lib/ui/src/asset/capacity.zig:4
pub const family_bytes_per_font: u32 = 64;Source: lib/ui/src/asset/embedded.zig:17
pub const faces = [_]Face{ .{ .family = "Noto Sans", .descriptor = .{ .family_len = "Noto Sans".len, .units_per_em = 1000, .weight = 400, .width = 5, .ascent = 1.069, .descent = -0.293, .coverage = .{ 0xa000020f, 0x00000002, 0, 0, 0, 0, 0, 0 }, }, .bytes = noto_bytes, }, .{ .family = "Iosevka", .descriptor = .{ .family_len = "Iosevka".len, .units_per_em = 1000, .weight = 400, .width = 5, .monospace = 1, .ascent = 0.965, .descent = -0.285, .coverage = .{ 0xa000020f, 0x00000002, 0, 0, 0, 0, 0, 0 }, }, .bytes = iosevka_bytes, },};Source: lib/ui/src/asset/resolve.zig:93
pub fn authored(registry: *const Registry, family_list: []const u8, weight: u16, slant: u8, fallback_out: []model.AssetHandle) Error!Authored { if (fallback_out.len < registry.font_used -| 1) return error.FallbackCapacityExceeded; var selected: ?model.AssetHandle = null; var used: usize = 0; var cursor: usize = 0; var monospace = false; while (nextFamily(family_list, &cursor)) |raw_family| { var decoded: [64]u8 = undefined; const family = if (css.token.hasEscape(raw_family)) css.token.unescape(raw_family, &decoded) orelse continue else raw_family; if (std.ascii.eqlIgnoreCase(family, "monospace")) monospace = true; const choice = primary(registry, .{ .family = family, .weight = weight, .slant = slant }); const face = choice.face orelse continue; const found = registry.font(face) catch unreachable; if (!std.ascii.eqlIgnoreCase(found.family, family)) continue; if (selected == null) { selected = face; } else if (!std.meta.eql(selected.?, face) and !containsHandle(fallback_out[0..used], face)) { fallback_out[used] = face; used += 1; } } const face = selected orelse primary(registry, .{ .family = "", .weight = weight, .slant = slant, .monospace = monospace, }).face; return .{ .face = face, .synthetic_slant = if (face) |handle| slant != 0 and registry.fonts[handle.index].slant == 0 else false, .fallback = fallback_out[0..used], };}Source: lib/ui/src/asset/resolve.zig:20
pub fn bit(value: Coverage) u64 { return @as(u64, 1) << @backingInt(value);}Source: lib/ui/src/asset/resolve.zig:26
/// The first four words use OS/2 Unicode-range positions. Word four bit zero/// denotes cmap coverage in the assigned emoji pictograph range.pub fn coverageForScripts(scripts: u64) [8]u32 { var mask: [8]u32 = @splat(0); if (scripts & bit(.latin) != 0) mask[0] |= 0x2000007f; if (scripts & bit(.cyrillic) != 0) mask[0] |= @as(u32, 1) << 9; if (scripts & bit(.greek) != 0) mask[0] |= @as(u32, 1) << 7; if (scripts & bit(.arabic) != 0) mask[0] |= @as(u32, 1) << 13; if (scripts & bit(.hebrew) != 0) mask[0] |= @as(u32, 1) << 11; if (scripts & bit(.devanagari) != 0) mask[0] |= @as(u32, 1) << 15; if (scripts & bit(.cjk) != 0) { mask[0] |= @as(u32, 1) << 28; mask[1] |= 0x29df0000; } if (scripts & bit(.emoji) != 0) mask[4] |= 1; return mask;}Source: lib/ui/src/asset/resolve.zig:153
pub fn primary(registry: *const Registry, request: Request) Primary { if (registry.font_used == 0) return .{ .face = null, .synthetic_slant = false }; const wanted = coverageForScripts(request.scripts); var chosen_face: ?model.AssetHandle = null; for (registry.fonts, 0..) |_, index| { const handle = model.AssetHandle{ .index = @intCast(index), .generation = registry.font_generation[index] }; if (!registry.hasFont(handle)) continue; if (chosen_face) |chosen| { if (preferPrimary(registry, handle, chosen, request, wanted)) chosen_face = handle; } else chosen_face = handle; } const face = chosen_face.?; return .{ .face = face, .synthetic_slant = request.slant != 0 and registry.fonts[face.index].slant == 0, };}Source: lib/ui/src/asset/resolve.zig:171
pub fn resolve(registry: *const Registry, request: Request, fallback_out: []model.AssetHandle) Error!Resolution { const selected = primary(registry, request); const face = selected.face orelse return .{ .face = null, .synthetic_slant = false, .fallback = fallback_out[0..0] }; const fallback = try scriptFallbacks(registry, request.scripts, &.{face}, fallback_out); return .{ .face = face, .synthetic_slant = selected.synthetic_slant, .fallback = fallback, };}Source: lib/ui/src/asset/resolve.zig:183
/// Orders faces outside an authored chain for one itemized script run.pub fn scriptFallbacks(registry: *const Registry, scripts: u64, excluded: []const model.AssetHandle, fallback_out: []model.AssetHandle) Error![]const model.AssetHandle { const wanted = coverageForScripts(scripts); var wanted_bits: usize = 0; for (wanted) |word| wanted_bits += @popCount(word); const bucket_count = wanted_bits + 1; var counts: [257]u32 = undefined; @memset(counts[0..bucket_count], 0); for (registry.fonts, 0..) |_, index| { const handle = model.AssetHandle{ .index = @intCast(index), .generation = registry.font_generation[index] }; if (!registry.hasFont(handle) or containsHandle(excluded, handle)) continue; counts[overlap(registry.fonts[index].coverage, wanted)] += 1; } var starts: [257]u32 = undefined; var used: u32 = 0; var score: usize = bucket_count; while (score > 0) { score -= 1; starts[score] = used; used += counts[score]; } if (fallback_out.len < used) return error.FallbackCapacityExceeded; for (registry.fonts, 0..) |_, index| { const handle = model.AssetHandle{ .index = @intCast(index), .generation = registry.font_generation[index] }; if (!registry.hasFont(handle) or containsHandle(excluded, handle)) continue; const rank = overlap(registry.fonts[index].coverage, wanted); fallback_out[starts[rank]] = handle; starts[rank] += 1; } return fallback_out[0..used];}Source: lib/ui/src/asset/resolve.zig:48
pub fn scriptsFromRuns(runs: []const unicode.ScriptRun, emoji_present: bool) u64 { var mask: u64 = if (emoji_present) bit(.emoji) else 0; for (runs) |run| { mask |= switch (run.script) { .latin => bit(.latin), .cyrillic => bit(.cyrillic), .han, .hiragana, .katakana, .hangul, .bopomofo => bit(.cjk), .greek => bit(.greek), .arabic => bit(.arabic), .hebrew => bit(.hebrew), .devanagari => bit(.devanagari), .common, .inherited, .unknown => 0, else => bit(.other), }; } return mask;}Source: lib/ui/src/asset/root.zig
const capacity = @import("capacity.zig");const model = @import("model.zig");const registry = @import("registry.zig");const resolution = @import("resolve.zig");const embedded = @import("embedded.zig");pub const AssetHandle = model.AssetHandle;pub const FontDescriptor = model.FontDescriptor;pub const ImageDescriptor = model.ImageDescriptor;pub const Bytes = model.Bytes;pub const Kind = model.Kind;pub const Error = model.Error;pub const Font = model.Font;pub const Image = model.Image;pub const Limits = capacity.Limits;pub const Capacity = capacity.Capacity;pub const CapacityError = capacity.Error;pub const family_bytes_per_font = capacity.family_bytes_per_font;pub const default_table_bytes = capacity.default_table_bytes;pub const Registry = registry.Registry;pub const Coverage = resolution.Coverage;pub const coverageBit = resolution.bit;pub const coverageForScripts = resolution.coverageForScripts;pub const scriptsFromRuns = resolution.scriptsFromRuns;pub const FontRequest = resolution.Request;pub const FontResolution = resolution.Resolution;pub const FontPrimary = resolution.Primary;pub const primaryFont = resolution.primary;pub const FontAuthored = resolution.Authored;pub const resolveAuthored = resolution.authored;pub const scriptFallbacks = resolution.scriptFallbacks;pub const Embedded = embedded.Embedded;pub const embedded_faces = embedded.faces;pub const openWithEmbedded = embedded.Embedded.open;pub const resolveFont = resolution.resolve;Source: lib/ui/src/root.zig:9
pub const asset = @import("asset/root.zig");Audit
| Definitions | 28 |
|---|---|
| Public names | 28 |
| Members | 65 |
| Version | 26.7.0 |
| Revision | daab053ee433 |