tiny.filigree.font.gdef
Defined in font.
API (8)
Actions
Public operations.
Gdef.glyphClassGdef.initGdef.ligatureCaretGdef.ligatureCaretCountGdef.markAttachmentClassGdef.markGlyphSetContainsGdef.variationDelta
Types and contracts
Public types and contracts.
Source
Source: lib/filigree/src/font/gdef.zig
zig
const std = @import("std");const binary = @import("binary.zig");const layout = @import("../layout/root.zig");const model = @import("model.zig");const variations = @import("variations.zig");const FontError = model.FontError;const GlyphClass = model.GlyphClass;const LigatureCaret = model.LigatureCaret;const Table = binary.Table;const VariationSetting = model.VariationSetting;const DeltaSetIndex = variations.DeltaSetIndex;const ItemVariationStore = variations.ItemVariationStore;pub const Gdef = struct { table: Table, glyph_class_def_offset: ?usize, mark_attach_class_def_offset: ?usize, mark_glyph_sets_def_offset: ?usize, lig_caret_list_offset: ?usize, variation_store: ?ItemVariationStore, pub fn init(data: []const u8, gdef_table: Table, axis_count: ?u16) FontError!Gdef { const bytes = data[gdef_table.offset..][0..gdef_table.len]; if (bytes.len < 12) return error.InvalidGdef; const major = try readGdefU16(bytes, 0); const minor = try readGdefU16(bytes, 2); if (major != 1 or (minor != 0 and minor != 2 and minor != 3)) return error.InvalidGdef; if (minor == 2 and bytes.len < 14) return error.InvalidGdef; if (minor == 3 and bytes.len < 18) return error.InvalidGdef; const glyph_class_def_relative = try readGdefU16(bytes, 4); const glyph_class_def_offset = if (glyph_class_def_relative == 0) null else try gdefChildOffset(bytes, 0, glyph_class_def_relative, 2); if (glyph_class_def_offset) |offset| { _ = layout.ClassDef.init(bytes, offset) catch return error.InvalidGdef; } const lig_caret_list_relative = try readGdefU16(bytes, 8); const lig_caret_list_offset = if (lig_caret_list_relative == 0) null else try gdefChildOffset(bytes, 0, lig_caret_list_relative, 4); if (lig_caret_list_offset) |offset| try validateGdefLigCaretList(bytes, offset); const mark_attach_class_def_relative = try readGdefU16(bytes, 10); const mark_attach_class_def_offset = if (mark_attach_class_def_relative == 0) null else try gdefChildOffset(bytes, 0, mark_attach_class_def_relative, 2); if (mark_attach_class_def_offset) |offset| { _ = layout.ClassDef.init(bytes, offset) catch return error.InvalidGdef; } const mark_glyph_sets_def_offset = if (minor >= 2) blk: { const relative = try readGdefU16(bytes, 12); if (relative == 0) break :blk null; const offset = try gdefChildOffset(bytes, 0, relative, 4); try validateGdefMarkGlyphSets(bytes, offset); break :blk offset; } else null; const variation_store = if (minor >= 3) blk: { const relative = try readGdefU32(bytes, 14); if (relative == 0) break :blk null; const offset = try gdefChildOffset32(bytes, 0, relative, 8); const variation_axis_count = axis_count orelse break :blk null; const store_table = Table{ .offset = gdef_table.offset + offset, .len = gdef_table.len - offset, }; break :blk ItemVariationStore.init(data, store_table, variation_axis_count) catch return error.InvalidGdef; } else null; return .{ .table = gdef_table, .glyph_class_def_offset = glyph_class_def_offset, .mark_attach_class_def_offset = mark_attach_class_def_offset, .mark_glyph_sets_def_offset = mark_glyph_sets_def_offset, .lig_caret_list_offset = lig_caret_list_offset, .variation_store = variation_store, }; } pub fn glyphClass(self: Gdef, data: []const u8, glyph_id: u32) FontError!GlyphClass { const glyph_class_def_offset = self.glyph_class_def_offset orelse return .unknown; const bytes = data[self.table.offset..][0..self.table.len]; const class_def = layout.ClassDef.init(bytes, glyph_class_def_offset) catch return error.InvalidGdef; return glyphClassFromValue(class_def.class(bytes, glyph_id) catch return error.InvalidGdef); } pub fn markAttachmentClass(self: Gdef, data: []const u8, glyph_id: u32) FontError!u16 { const mark_attach_class_def_offset = self.mark_attach_class_def_offset orelse return 0; const bytes = data[self.table.offset..][0..self.table.len]; const class_def = layout.ClassDef.init(bytes, mark_attach_class_def_offset) catch return error.InvalidGdef; return class_def.class(bytes, glyph_id) catch return error.InvalidGdef; } pub fn markGlyphSetContains(self: Gdef, data: []const u8, set_index: u16, glyph_id: u32) FontError!bool { const mark_glyph_sets_def_offset = self.mark_glyph_sets_def_offset orelse return false; const bytes = data[self.table.offset..][0..self.table.len]; if (try readGdefU16(bytes, mark_glyph_sets_def_offset) != 1) return error.InvalidGdef; const set_count = try readGdefU16(bytes, mark_glyph_sets_def_offset + 2); if (set_index >= set_count) return error.InvalidGdef; const coverage_offsets = mark_glyph_sets_def_offset + 4; if (!hasGdefBytes(bytes, coverage_offsets, @as(usize, set_count) * 4)) return error.InvalidGdef; const coverage_relative = try readGdefU32(bytes, coverage_offsets + @as(usize, set_index) * 4); const coverage_offset = try gdefChildOffset32(bytes, mark_glyph_sets_def_offset, coverage_relative, 2); const coverage = layout.Coverage.init(bytes, coverage_offset) catch return error.InvalidGdef; return (coverage.index(bytes, glyph_id) catch return error.InvalidGdef) != null; } pub fn ligatureCaretCount(self: Gdef, data: []const u8, glyph_id: u32) FontError!u16 { const lig_caret_list_offset = self.lig_caret_list_offset orelse return 0; const bytes = data[self.table.offset..][0..self.table.len]; const lig_glyph_offset = (try gdefLigGlyphOffset(bytes, lig_caret_list_offset, glyph_id)) orelse return 0; return try readGdefU16(bytes, lig_glyph_offset); } pub fn ligatureCaret(self: Gdef, data: []const u8, glyph_id: u32, caret_index: usize) FontError!?LigatureCaret { const lig_caret_list_offset = self.lig_caret_list_offset orelse return null; const bytes = data[self.table.offset..][0..self.table.len]; const lig_glyph_offset = (try gdefLigGlyphOffset(bytes, lig_caret_list_offset, glyph_id)) orelse return null; const caret_count = try readGdefU16(bytes, lig_glyph_offset); if (caret_index >= caret_count) return null; const caret_offsets = lig_glyph_offset + 2; if (!hasGdefBytes(bytes, caret_offsets, @as(usize, caret_count) * 2)) return error.InvalidGdef; const caret_value_offset = try gdefChildOffset( bytes, lig_glyph_offset, try readGdefU16(bytes, caret_offsets + caret_index * 2), 2, ); return try readGdefCaretValue(bytes, caret_value_offset); } pub fn variationDelta(self: Gdef, data: []const u8, face: anytype, settings: []const VariationSetting, index: DeltaSetIndex) FontError!i32 { const store = self.variation_store orelse return 0; return try store.delta(data, face, settings, index); }};fn glyphClassFromValue(value: u16) GlyphClass { return switch (value) { 1 => .base, 2 => .ligature, 3 => .mark, 4 => .component, else => .unknown, };}fn validateGdefLigCaretList(data: []const u8, lig_caret_list_offset: usize) FontError!void { if (!hasGdefBytes(data, lig_caret_list_offset, 4)) return error.InvalidGdef; const coverage_offset = try gdefChildOffset(data, lig_caret_list_offset, try readGdefU16(data, lig_caret_list_offset), 2); _ = layout.Coverage.init(data, coverage_offset) catch return error.InvalidGdef; const lig_glyph_count = try readGdefU16(data, lig_caret_list_offset + 2); const lig_glyph_offsets = lig_caret_list_offset + 4; if (!hasGdefBytes(data, lig_glyph_offsets, @as(usize, lig_glyph_count) * 2)) return error.InvalidGdef; for (0..lig_glyph_count) |lig_glyph_index| { const lig_glyph_offset = try gdefChildOffset( data, lig_caret_list_offset, try readGdefU16(data, lig_glyph_offsets + lig_glyph_index * 2), 2, ); const caret_count = try readGdefU16(data, lig_glyph_offset); const caret_offsets = lig_glyph_offset + 2; if (!hasGdefBytes(data, caret_offsets, @as(usize, caret_count) * 2)) return error.InvalidGdef; for (0..caret_count) |caret_index| { const caret_value_offset = try gdefChildOffset( data, lig_glyph_offset, try readGdefU16(data, caret_offsets + caret_index * 2), 2, ); _ = try readGdefCaretValue(data, caret_value_offset); } }}fn validateGdefMarkGlyphSets(data: []const u8, mark_glyph_sets_offset: usize) FontError!void { if (!hasGdefBytes(data, mark_glyph_sets_offset, 4)) return error.InvalidGdef; if (try readGdefU16(data, mark_glyph_sets_offset) != 1) return error.InvalidGdef; const set_count = try readGdefU16(data, mark_glyph_sets_offset + 2); const coverage_offsets = mark_glyph_sets_offset + 4; if (!hasGdefBytes(data, coverage_offsets, @as(usize, set_count) * 4)) return error.InvalidGdef; for (0..set_count) |set_index| { const coverage_offset = try gdefChildOffset32( data, mark_glyph_sets_offset, try readGdefU32(data, coverage_offsets + set_index * 4), 2, ); _ = layout.Coverage.init(data, coverage_offset) catch return error.InvalidGdef; }}fn gdefLigGlyphOffset(data: []const u8, lig_caret_list_offset: usize, glyph_id: u32) FontError!?usize { if (!hasGdefBytes(data, lig_caret_list_offset, 4)) return error.InvalidGdef; const coverage_offset = try gdefChildOffset(data, lig_caret_list_offset, try readGdefU16(data, lig_caret_list_offset), 2); const coverage = layout.Coverage.init(data, coverage_offset) catch return error.InvalidGdef; const coverage_index = (coverage.index(data, glyph_id) catch return error.InvalidGdef) orelse return null; const lig_glyph_count = try readGdefU16(data, lig_caret_list_offset + 2); if (coverage_index >= lig_glyph_count) return error.InvalidGdef; const lig_glyph_offsets = lig_caret_list_offset + 4; if (!hasGdefBytes(data, lig_glyph_offsets, @as(usize, lig_glyph_count) * 2)) return error.InvalidGdef; return try gdefChildOffset( data, lig_caret_list_offset, try readGdefU16(data, lig_glyph_offsets + @as(usize, coverage_index) * 2), 2, );}fn readGdefCaretValue(data: []const u8, caret_value_offset: usize) FontError!?LigatureCaret { const format = try readGdefU16(data, caret_value_offset); return switch (format) { 1 => blk: { if (!hasGdefBytes(data, caret_value_offset, 4)) return error.InvalidGdef; break :blk .{ .coordinate = try readGdefI16(data, caret_value_offset + 2) }; }, 2 => blk: { if (!hasGdefBytes(data, caret_value_offset, 4)) return error.InvalidGdef; break :blk null; }, 3 => blk: { if (!hasGdefBytes(data, caret_value_offset, 6)) return error.InvalidGdef; const coordinate = try readGdefI16(data, caret_value_offset + 2); const device_offset = try readGdefU16(data, caret_value_offset + 4); if (device_offset != 0) _ = try gdefChildOffset(data, caret_value_offset, device_offset, 2); break :blk .{ .coordinate = coordinate }; }, else => error.InvalidGdef, };}fn gdefChildOffset(data: []const u8, base: usize, relative_offset: u16, min_len: usize) FontError!usize { const relative: usize = relative_offset; if (relative == 0 or base > data.len or relative > data.len - base) return error.InvalidGdef; const offset = base + relative; if (!hasGdefBytes(data, offset, min_len)) return error.InvalidGdef; return offset;}fn gdefChildOffset32(data: []const u8, base: usize, relative_offset: u32, min_len: usize) FontError!usize { if (relative_offset == 0 or relative_offset > std.math.maxInt(usize)) return error.InvalidGdef; const relative: usize = @intCast(relative_offset); if (base > data.len or relative > data.len - base) return error.InvalidGdef; const offset = base + relative; if (!hasGdefBytes(data, offset, min_len)) return error.InvalidGdef; return offset;}fn hasGdefBytes(data: []const u8, offset: usize, len: usize) bool { return offset <= data.len and len <= data.len - offset;}fn readGdefU16(data: []const u8, offset: usize) FontError!u16 { if (!hasGdefBytes(data, offset, 2)) return error.InvalidGdef; return std.mem.readInt(u16, data[offset..][0..2], .big);}fn readGdefI16(data: []const u8, offset: usize) FontError!i16 { return @bitCast(try readGdefU16(data, offset));}fn readGdefU32(data: []const u8, offset: usize) FontError!u32 { if (!hasGdefBytes(data, offset, 4)) return error.InvalidGdef; return std.mem.readInt(u32, data[offset..][0..4], .big);}test "GDEF child offsets stay inside table data" { const data = @as([10]u8, @splat(0)); try std.testing.expectEqual(@as(usize, 6), try gdefChildOffset(&data, 2, 4, 2)); try std.testing.expectError(error.InvalidGdef, gdefChildOffset(&data, 2, 0, 2)); try std.testing.expectError(error.InvalidGdef, gdefChildOffset(&data, 10, 1, 2)); try std.testing.expectError(error.InvalidGdef, gdefChildOffset(&data, 8, 1, 2));}test "GDEF glyph class values map to public classes" { try std.testing.expectEqual(GlyphClass.unknown, glyphClassFromValue(0)); try std.testing.expectEqual(GlyphClass.base, glyphClassFromValue(1)); try std.testing.expectEqual(GlyphClass.ligature, glyphClassFromValue(2)); try std.testing.expectEqual(GlyphClass.mark, glyphClassFromValue(3)); try std.testing.expectEqual(GlyphClass.component, glyphClassFromValue(4)); try std.testing.expectEqual(GlyphClass.unknown, glyphClassFromValue(5));}test "GDEF caret values read supported coordinate formats" { const format_1 = [_]u8{ 0, 1, 0, 250, }; const format_2 = [_]u8{ 0, 2, 0, 7, }; const format_3 = [_]u8{ 0, 3, 0xff, 0x9c, 0, 0, }; try std.testing.expectEqual(@as(i16, 250), (try readGdefCaretValue(&format_1, 0)).?.coordinate); try std.testing.expect((try readGdefCaretValue(&format_2, 0)) == null); try std.testing.expectEqual(@as(i16, -100), (try readGdefCaretValue(&format_3, 0)).?.coordinate); try std.testing.expectError(error.InvalidGdef, readGdefCaretValue(&[_]u8{ 0, 4 }, 0));}Source: lib/filigree/src/font/root.zig:7
zig
pub const gdef = @import("gdef.zig");Complete call list for font.gdef.Gdef.init
7 direct calls.
lib.filigree.src.font.gdef.gdefChildOffset[function] — private source atlib/filigree/src/font/gdef.zig:243in nearest public ownertiny.filigree.font.gdeflib.filigree.src.font.gdef.gdefChildOffset32[function] — private source atlib/filigree/src/font/gdef.zig:251in nearest public ownertiny.filigree.font.gdeflib.filigree.src.font.gdef.readGdefU16[function] — private source atlib/filigree/src/font/gdef.zig:264in nearest public ownertiny.filigree.font.gdeflib.filigree.src.font.gdef.readGdefU32[function] — private source atlib/filigree/src/font/gdef.zig:273in nearest public ownertiny.filigree.font.gdeflib.filigree.src.font.gdef.validateGdefLigCaretList[function] — private source atlib/filigree/src/font/gdef.zig:155in nearest public ownertiny.filigree.font.gdeflib.filigree.src.font.gdef.validateGdefMarkGlyphSets[function] — private source atlib/filigree/src/font/gdef.zig:186in nearest public ownertiny.filigree.font.gdeftiny.filigree.font.variations.ItemVariationStore.init[function] atlib/filigree/src/font/variations.zig:363
Audit
| Definitions | 9 |
|---|---|
| Public names | 9 |
| Members | 6 |
| Version | 26.7.0 |
| Revision | daab053ee433 |