Skip to documentation
SLOP

tiny.filigree.font.variations

Reference tiny.filigree font variations

Defined in font.

API (28)

Actions

Public operations.

Types and contracts

Public types and contracts.

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

Source

Called byCallsNo direct callsprivate sourcelib.filigree.src.font.faceinitDirectoryImplfont.variations.Avarinit
Static calls · unresolved targets: 1 · external targets: 0.
Called byCallsNo direct callersprivate sourcelib.filigree.src.font.variations.AvarsegmentMapOffsetprivate sourcelib.filigree.src.font.variationsavarHasRequiredMapsprivate sourcelib.filigree.src.font.variationsavarMapAtprivate sourcelib.filigree.src.font.variationsclampFixed16font.variations.Avarmap
Static calls · unresolved targets: 1 · external targets: 0.
Called byCallsNo direct callsfont.variations.FvaraxisIndexfont.variations.Fvaraxis
Static calls · unresolved targets: 3 · external targets: 0.
Called byCallsNo direct callersfont.variations.Fvaraxisfont.variations.FvaraxisIndex
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callsprivate sourcelib.filigree.src.font.faceinitDirectoryImplfont.variations.Fvarinit
Static calls · unresolved targets: 1 · external targets: 1.
Called byCallsNo direct callersfont.variations.ItemVariationStoredeltafont.variations.HvaradvanceWidthDelta
Static calls · unresolved targets: 0 · external targets: 1.
Called byCallsprivate sourcelib.filigree.src.font.faceinitDirectoryImplfont.variations.ItemVariationStoreinitprivate sourcelib.filigree.src.font.variationsoptionalDeltaSetIndexMapfont.variationsvariationChildTablefont.variations.Hvarinit
Static calls · unresolved targets: 2 · external targets: 0.
Called byCallsfont.variations.HvaradvanceWidthDeltafont.variations.VvaradvanceHeightDeltaprivate sourcelib.filigree.src.font.variations.ItemVariatio...deltaprivate sourcelib.filigree.src.font.variations.ItemVariatio...initfont.variations.ItemVariationStoreitemVariationDatafont.variations.ItemVariationStoredelta
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsfont.gdef.Gdefinitfont.variations.Hvarinitfont.variations.Mvarinitfont.variations.Vvarinitprivate sourcelib.filigree.src.font.variations.ItemVariatio...initprivate sourcelib.filigree.src.font.variations.VariationReg...initfont.variationsvariationChildTablefont.variations.ItemVariationStoreinit
Static calls · unresolved targets: 2 · external targets: 1.
Called byCallsfont.variations.ItemVariationStoredeltafont.variationsvariationChildTablefont.variations.ItemVariationStoreitemVariationData
Static calls · unresolved targets: 1 · external targets: 0.
Called byCallsprivate sourcelib.filigree.src.font.faceinitDirectoryImplfont.variations.ItemVariationStoreinitfont.variationsvariationChildTablefont.variations.Mvarinit
Static calls · unresolved targets: 2 · external targets: 1.
Called byCallsNo direct callersprivate sourcelib.filigree.src.font.variations.MvarrecordOffsetfont.variations.MvarvalueDelta
Static calls · unresolved targets: 2 · external targets: 1.
Called byCallsNo direct callersfont.variations.ItemVariationStoredeltafont.variations.VvaradvanceHeightDelta
Static calls · unresolved targets: 0 · external targets: 1.
Called byCallsprivate sourcelib.filigree.src.font.faceinitDirectoryImplfont.variations.ItemVariationStoreinitprivate sourcelib.filigree.src.font.variationsoptionalDeltaSetIndexMapfont.variationsvariationChildTablefont.variations.Vvarinit
Static calls · unresolved targets: 2 · external targets: 0.
Called byCallsNo direct callsprivate sourcelib.filigree.src.font.faceadvanceHeightForVariationsImplprivate sourcelib.filigree.src.font.faceadvanceWidthForVariationsImplfont.variationsclampDesignMetric
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callsprivate sourcelib.filigree.src.font.variationsroundVariationDeltafont.variationsclampI32
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callsprivate sourcelib.filigree.src.font.facenormalizedCoordinateAtImplfont.variationsfixed16FromFloat
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callsprivate sourcelib.filigree.src.font.facenormalizedCoordinateAtImplfont.variationsfixed16ToF2Dot14
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsprivate sourcelib.filigree.src.font.facenormalizedCoordinateAtImplprivate sourcelib.filigree.src.font.variationsclampFixed16font.variationsnormalizeVariationAxis
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callsfont.variationsvariationChildTablefont.variationsvariationChildOffset
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsfont.variations.Hvarinitfont.variations.ItemVariationStoreinitfont.variations.ItemVariationStoreitemVariationDatafont.variations.Mvarinitfont.variations.Vvarinitprivate sourcelib.filigree.src.font.variationsoptionalDeltaSetIndexMapfont.variationsvariationChildOffsetfont.variationsvariationChildTable
Static calls · unresolved targets: 0 · external targets: 0.

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

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

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

zig
const std = @import("std");const binary = @import("binary.zig");const model = @import("model.zig");const FontError = model.FontError;const Table = binary.Table;const Tag = model.Tag;const VariationAxis = model.VariationAxis;const VariationSetting = model.VariationSetting;const readI8 = binary.readI8;const readI16 = binary.readI16;const readI32 = binary.readI32;const readU16 = binary.readU16;const readU32 = binary.readU32;pub const Fvar = struct {    table: Table,    axes_offset: usize,    axis_count: u16,    axis_size: u16,    pub fn init(data: []const u8, fvar_table: Table) FontError!Fvar {        if (fvar_table.len < 16) return error.InvalidVariations;        const major = try readU16(data, fvar_table.offset);        const minor = try readU16(data, fvar_table.offset + 2);        if (major != 1 or minor != 0) return error.InvalidVariations;        const axes_array_offset = try readU16(data, fvar_table.offset + 4);        const axis_count = try readU16(data, fvar_table.offset + 8);        const axis_size = try readU16(data, fvar_table.offset + 10);        const instance_count = try readU16(data, fvar_table.offset + 12);        const instance_size = try readU16(data, fvar_table.offset + 14);        if (axis_count == 0 or axis_size < 20) return error.InvalidVariations;        if (axes_array_offset > fvar_table.len) return error.InvalidVariations;        const axes_offset = fvar_table.offset + axes_array_offset;        const axes_len = @as(usize, axis_count) * @as(usize, axis_size);        if (axes_len > fvar_table.len - axes_array_offset) return error.InvalidVariations;        const instances_offset = axes_array_offset + axes_len;        const minimum_instance_size = @as(usize, axis_count) * 4 + 4;        if (instance_count != 0 and instance_size < minimum_instance_size) return error.InvalidVariations;        const instances_len = @as(usize, instance_count) * @as(usize, instance_size);        if (instances_len > fvar_table.len - instances_offset) return error.InvalidVariations;        var result = Fvar{            .table = fvar_table,            .axes_offset = axes_offset,            .axis_count = axis_count,            .axis_size = axis_size,        };        for (0..axis_count) |axis_index| {            _ = try result.axis(data, axis_index);        }        return result;    }    pub fn axis(self: Fvar, data: []const u8, axis_index: usize) FontError!VariationAxis {        if (axis_index >= self.axis_count) return error.InvalidVariations;        const offset = self.axes_offset + axis_index * @as(usize, self.axis_size);        const variation_axis = VariationAxis{            .tag = try readU32(data, offset),            .min_value = try readI32(data, offset + 4),            .default_value = try readI32(data, offset + 8),            .max_value = try readI32(data, offset + 12),            .flags = try readU16(data, offset + 16),            .name_id = try readU16(data, offset + 18),        };        if (variation_axis.min_value > variation_axis.default_value or variation_axis.default_value > variation_axis.max_value) return error.InvalidVariations;        return variation_axis;    }    pub fn axisIndex(self: Fvar, data: []const u8, axis_tag: Tag) FontError!?usize {        for (0..self.axis_count) |axis_index| {            const variation_axis = try self.axis(data, axis_index);            if (variation_axis.tag == axis_tag) return axis_index;        }        return null;    }};pub const Avar = struct {    table: Table,    axis_count: u16,    pub fn init(data: []const u8, avar_table: Table, expected_axis_count: u16) FontError!Avar {        if (avar_table.len < 8) return error.InvalidVariations;        const major = try readU16(data, avar_table.offset);        const minor = try readU16(data, avar_table.offset + 2);        if (major != 1 or minor != 0) return error.InvalidVariations;        const axis_count = try readU16(data, avar_table.offset + 6);        if (axis_count != expected_axis_count) return error.InvalidVariations;        var cursor = avar_table.offset + 8;        const end = avar_table.offset + avar_table.len;        for (0..axis_count) |_| {            if (cursor > end or end - cursor < 2) return error.InvalidVariations;            const position_map_count = try readU16(data, cursor);            cursor += 2;            const records_len = @as(usize, position_map_count) * 4;            if (records_len > end - cursor) return error.InvalidVariations;            cursor += records_len;        }        return .{ .table = avar_table, .axis_count = axis_count };    }    pub fn map(self: Avar, data: []const u8, axis_index: usize, value: i32) FontError!i32 {        const map_offset = try self.segmentMapOffset(data, axis_index);        const count = try readU16(data, map_offset);        if (count < 3) return value;        const records = map_offset + 2;        if (!try avarHasRequiredMaps(data, records, count)) return value;        var previous_valid: ?AvarMap = null;        var start: ?AvarMap = null;        var end: ?AvarMap = null;        for (0..count) |map_index| {            const map_record = try avarMapAt(data, records, map_index);            if (previous_valid) |previous| {                if (map_record.from <= previous.from or map_record.to < previous.to) continue;            }            previous_valid = map_record;            if (map_record.from <= value) start = map_record;            if (map_record.from >= value) {                end = map_record;                break;            }        }        const start_map = start orelse return value;        const end_map = end orelse return value;        if (start_map.from == value) return start_map.to;        if (end_map.from == value) return end_map.to;        if (start_map.from == end_map.from) return value;        const numerator = @as(i64, value - start_map.from) * @as(i64, end_map.to - start_map.to);        const denominator = @as(i64, end_map.from - start_map.from);        const mapped = @as(i64, start_map.to) + @divTrunc(numerator, denominator);        return clampFixed16(mapped);    }    fn segmentMapOffset(self: Avar, data: []const u8, axis_index: usize) FontError!usize {        if (axis_index >= self.axis_count) return error.InvalidVariations;        var cursor = self.table.offset + 8;        for (0..axis_index) |_| {            const count = try readU16(data, cursor);            cursor += 2 + @as(usize, count) * 4;        }        return cursor;    }};const AvarMap = struct {    from: i32,    to: i32,};pub const DeltaSetIndex = struct {    outer: u32,    inner: u32,};pub const Hvar = struct {    store: ItemVariationStore,    advance_map: ?DeltaSetIndexMap,    pub fn init(data: []const u8, hvar_table: Table, axis_count: u16) FontError!Hvar {        if (hvar_table.len < 20) return error.InvalidVariations;        const major = try readU16(data, hvar_table.offset);        const minor = try readU16(data, hvar_table.offset + 2);        if (major != 1 or minor != 0) return error.InvalidVariations;        const store_table = try variationChildTable(hvar_table, try readU32(data, hvar_table.offset + 4), 8);        const store = try ItemVariationStore.init(data, store_table, axis_count);        const advance_map = try optionalDeltaSetIndexMap(data, hvar_table, try readU32(data, hvar_table.offset + 8));        _ = try optionalDeltaSetIndexMap(data, hvar_table, try readU32(data, hvar_table.offset + 12));        _ = try optionalDeltaSetIndexMap(data, hvar_table, try readU32(data, hvar_table.offset + 16));        return .{            .store = store,            .advance_map = advance_map,        };    }    pub fn advanceWidthDelta(self: Hvar, data: []const u8, face: anytype, settings: []const VariationSetting, glyph_id: u32) FontError!i32 {        const delta_index = if (self.advance_map) |mapping|            try mapping.index(data, glyph_id)        else            DeltaSetIndex{ .outer = 0, .inner = glyph_id };        return try self.store.delta(data, face, settings, delta_index);    }};pub const Vvar = struct {    store: ItemVariationStore,    advance_map: ?DeltaSetIndexMap,    pub fn init(data: []const u8, vvar_table: Table, axis_count: u16) FontError!Vvar {        if (vvar_table.len < 24) return error.InvalidVariations;        const major = try readU16(data, vvar_table.offset);        const minor = try readU16(data, vvar_table.offset + 2);        if (major != 1 or minor != 0) return error.InvalidVariations;        const store_table = try variationChildTable(vvar_table, try readU32(data, vvar_table.offset + 4), 8);        const store = try ItemVariationStore.init(data, store_table, axis_count);        const advance_map = try optionalDeltaSetIndexMap(data, vvar_table, try readU32(data, vvar_table.offset + 8));        _ = try optionalDeltaSetIndexMap(data, vvar_table, try readU32(data, vvar_table.offset + 12));        _ = try optionalDeltaSetIndexMap(data, vvar_table, try readU32(data, vvar_table.offset + 16));        _ = try optionalDeltaSetIndexMap(data, vvar_table, try readU32(data, vvar_table.offset + 20));        return .{            .store = store,            .advance_map = advance_map,        };    }    pub fn advanceHeightDelta(self: Vvar, data: []const u8, face: anytype, settings: []const VariationSetting, glyph_id: u32) FontError!i32 {        const delta_index = if (self.advance_map) |mapping|            try mapping.index(data, glyph_id)        else            DeltaSetIndex{ .outer = 0, .inner = glyph_id };        return try self.store.delta(data, face, settings, delta_index);    }};pub const Mvar = struct {    store: ?ItemVariationStore,    records_offset: usize,    value_record_size: u16,    value_record_count: u16,    pub fn init(data: []const u8, mvar_table: Table, axis_count: u16) FontError!Mvar {        if (mvar_table.len < 12) return error.InvalidVariations;        const major = try readU16(data, mvar_table.offset);        const minor = try readU16(data, mvar_table.offset + 2);        const reserved = try readU16(data, mvar_table.offset + 4);        if (major != 1 or minor != 0 or reserved != 0) return error.InvalidVariations;        const value_record_size = try readU16(data, mvar_table.offset + 6);        const value_record_count = try readU16(data, mvar_table.offset + 8);        const store_offset = try readU16(data, mvar_table.offset + 10);        if (value_record_size < 8) return error.InvalidVariations;        const records_len = @as(u64, value_record_count) * @as(u64, value_record_size);        if (records_len > @as(u64, mvar_table.len - 12)) return error.InvalidVariations;        const records_len_usize: usize = @intCast(records_len);        const store = if (value_record_count == 0) blk: {            if (store_offset != 0) return error.InvalidVariations;            break :blk null;        } else blk: {            if (store_offset == 0) return error.InvalidVariations;            const store_offset_usize: usize = store_offset;            if (store_offset_usize < 12 + records_len_usize) return error.InvalidVariations;            break :blk try ItemVariationStore.init(                data,                try variationChildTable(mvar_table, store_offset, 8),                axis_count,            );        };        const result = Mvar{            .store = store,            .records_offset = mvar_table.offset + 12,            .value_record_size = value_record_size,            .value_record_count = value_record_count,        };        var previous: ?Tag = null;        for (0..value_record_count) |record_index| {            const current = try readU32(data, result.recordOffset(record_index));            if (previous) |previous_tag| {                if (current <= previous_tag) return error.InvalidVariations;            }            previous = current;        }        return result;    }    pub fn valueDelta(self: Mvar, data: []const u8, face: anytype, settings: []const VariationSetting, metric_tag: Tag) FontError!i32 {        const store = self.store orelse return 0;        var left: usize = 0;        var right: usize = self.value_record_count;        while (left < right) {            const mid = left + (right - left) / 2;            const offset = self.recordOffset(mid);            const current = try readU32(data, offset);            if (metric_tag < current) {                right = mid;            } else if (metric_tag > current) {                left = mid + 1;            } else {                return try store.delta(data, face, settings, .{                    .outer = try readU16(data, offset + 4),                    .inner = try readU16(data, offset + 6),                });            }        }        return 0;    }    fn recordOffset(self: Mvar, record_index: usize) usize {        return self.records_offset + record_index * @as(usize, self.value_record_size);    }};const DeltaSetIndexMap = struct {    table: Table,    map_count: u32,    data_offset: usize,    entry_size: u8,    inner_bit_count: u5,    pub fn init(data: []const u8, map_table: Table) FontError!DeltaSetIndexMap {        if (map_table.len < 4) return error.InvalidVariations;        const format = data[map_table.offset];        const entry_format = data[map_table.offset + 1];        if ((entry_format & 0xc0) != 0) return error.InvalidVariations;        const entry_size: u8 = ((entry_format >> 4) & 0x03) + 1;        const inner_bit_count: u5 = @intCast((entry_format & 0x0f) + 1);        const header_len: usize = switch (format) {            0 => 4,            1 => 6,            else => return error.InvalidVariations,        };        if (map_table.len < header_len) return error.InvalidVariations;        const map_count = switch (format) {            0 => @as(u32, try readU16(data, map_table.offset + 2)),            1 => try readU32(data, map_table.offset + 2),            else => unreachable,        };        if (map_count == 0) return error.InvalidVariations;        if (@as(u64, map_count) * @as(u64, entry_size) > @as(u64, map_table.len - header_len)) return error.InvalidVariations;        return .{            .table = map_table,            .map_count = map_count,            .data_offset = map_table.offset + header_len,            .entry_size = entry_size,            .inner_bit_count = inner_bit_count,        };    }    pub fn index(self: DeltaSetIndexMap, data: []const u8, glyph_id: u32) FontError!DeltaSetIndex {        const entry_index = if (glyph_id < self.map_count) glyph_id else self.map_count - 1;        const entry_offset = self.data_offset + @as(usize, @intCast(entry_index)) * @as(usize, self.entry_size);        if (entry_offset < self.table.offset or entry_offset > self.table.offset + self.table.len or @as(usize, self.entry_size) > self.table.offset + self.table.len - entry_offset) return error.InvalidVariations;        var packed_index: u32 = 0;        for (0..self.entry_size) |byte_index| {            packed_index = (packed_index << 8) | @as(u32, data[entry_offset + byte_index]);        }        const inner_mask = (@as(u32, 1) << self.inner_bit_count) - 1;        return .{            .outer = packed_index >> self.inner_bit_count,            .inner = packed_index & inner_mask,        };    }};pub const ItemVariationStore = struct {    table: Table,    region_list: VariationRegionList,    data_count: u16,    data_offsets_offset: usize,    pub fn init(data: []const u8, store_table: Table, axis_count: u16) FontError!ItemVariationStore {        if (store_table.len < 8) return error.InvalidVariations;        if (try readU16(data, store_table.offset) != 1) return error.InvalidVariations;        const region_list = try VariationRegionList.init(            data,            try variationChildTable(store_table, try readU32(data, store_table.offset + 2), 4),            axis_count,        );        const data_count = try readU16(data, store_table.offset + 6);        if (@as(u64, data_count) * 4 > @as(u64, store_table.len - 8)) return error.InvalidVariations;        const result = ItemVariationStore{            .table = store_table,            .region_list = region_list,            .data_count = data_count,            .data_offsets_offset = store_table.offset + 8,        };        for (0..data_count) |data_index| {            const item_data = try result.itemVariationData(data, data_index);            if (item_data) |subtable| _ = try ItemVariationData.init(data, subtable, region_list.region_count);        }        return result;    }    pub fn delta(self: ItemVariationStore, data: []const u8, face: anytype, settings: []const VariationSetting, index: DeltaSetIndex) FontError!i32 {        if (index.outer >= self.data_count) return 0;        const item_data_table = (try self.itemVariationData(data, @intCast(index.outer))) orelse return 0;        const item_data = try ItemVariationData.init(data, item_data_table, self.region_list.region_count);        return try item_data.delta(data, self.region_list, face, settings, index.inner);    }    pub fn itemVariationData(self: ItemVariationStore, data: []const u8, data_index: usize) FontError!?Table {        if (data_index >= self.data_count) return null;        const relative_offset = try readU32(data, self.data_offsets_offset + data_index * 4);        if (relative_offset == 0) return null;        return try variationChildTable(self.table, relative_offset, 6);    }};const VariationRegionList = struct {    table: Table,    axis_count: u16,    region_count: u16,    pub fn init(data: []const u8, region_table: Table, expected_axis_count: u16) FontError!VariationRegionList {        if (region_table.len < 4) return error.InvalidVariations;        const axis_count = try readU16(data, region_table.offset);        const region_count = try readU16(data, region_table.offset + 2);        if (axis_count != expected_axis_count) return error.InvalidVariations;        if ((region_count & 0x8000) != 0) return error.InvalidVariations;        const region_record_len = @as(usize, axis_count) * 6;        if (@as(u64, region_count) * @as(u64, region_record_len) > @as(u64, region_table.len - 4)) return error.InvalidVariations;        return .{            .table = region_table,            .axis_count = axis_count,            .region_count = region_count,        };    }    pub fn scalar(self: VariationRegionList, data: []const u8, face: anytype, settings: []const VariationSetting, region_index: u16) FontError!i32 {        if (region_index >= self.region_count) return error.InvalidVariations;        const region_offset = self.table.offset + 4 + @as(usize, region_index) * @as(usize, self.axis_count) * 6;        var region_scalar: i64 = variationScalarOne;        for (0..self.axis_count) |axis_index| {            const axis_offset = region_offset + axis_index * 6;            const axis_scalar = variationAxisScalar(                try readI16(data, axis_offset),                try readI16(data, axis_offset + 2),                try readI16(data, axis_offset + 4),                try face.normalizedCoordinateAt(settings, axis_index),            );            region_scalar = @divTrunc(region_scalar * axis_scalar, variationScalarOne);            if (region_scalar == 0) return 0;        }        return @intCast(region_scalar);    }};const ItemVariationData = struct {    item_count: u16,    word_delta_count: u16,    region_index_count: u16,    long_words: bool,    region_indexes_offset: usize,    deltas_offset: usize,    row_len: usize,    pub fn init(data: []const u8, item_table: Table, region_count: u16) FontError!ItemVariationData {        if (item_table.len < 6) return error.InvalidVariations;        const item_count = try readU16(data, item_table.offset);        const packed_word_delta_count = try readU16(data, item_table.offset + 2);        const long_words = (packed_word_delta_count & 0x8000) != 0;        const word_delta_count = packed_word_delta_count & 0x7fff;        const region_index_count = try readU16(data, item_table.offset + 4);        if (word_delta_count > region_index_count) return error.InvalidVariations;        const region_indexes_offset = item_table.offset + 6;        const region_indexes_len = @as(usize, region_index_count) * 2;        if (region_indexes_len > item_table.len - 6) return error.InvalidVariations;        for (0..region_index_count) |region_index_offset| {            const region_index = try readU16(data, region_indexes_offset + region_index_offset * 2);            if (region_index >= region_count) return error.InvalidVariations;        }        const deltas_offset = region_indexes_offset + region_indexes_len;        const row_units = @as(usize, region_index_count) + @as(usize, word_delta_count);        const row_len = if (long_words) row_units * 2 else row_units;        if (@as(u64, item_count) * @as(u64, row_len) > @as(u64, item_table.offset + item_table.len - deltas_offset)) return error.InvalidVariations;        return .{            .item_count = item_count,            .word_delta_count = word_delta_count,            .region_index_count = region_index_count,            .long_words = long_words,            .region_indexes_offset = region_indexes_offset,            .deltas_offset = deltas_offset,            .row_len = row_len,        };    }    pub fn delta(self: ItemVariationData, data: []const u8, region_list: VariationRegionList, face: anytype, settings: []const VariationSetting, inner_index: u32) FontError!i32 {        if (inner_index >= self.item_count) return 0;        const row_offset = self.deltas_offset + @as(usize, @intCast(inner_index)) * self.row_len;        var accumulated: i64 = 0;        for (0..self.region_index_count) |delta_index| {            const delta_value = try self.deltaValue(data, row_offset, delta_index);            if (delta_value == 0) continue;            const region_index = try readU16(data, self.regionIndexesOffset(delta_index));            const scalar = try region_list.scalar(data, face, settings, region_index);            accumulated += @as(i64, delta_value) * @as(i64, scalar);        }        return roundVariationDelta(accumulated);    }    fn deltaValue(self: ItemVariationData, data: []const u8, row_offset: usize, delta_index: usize) FontError!i32 {        if (self.long_words) {            if (delta_index < self.word_delta_count) return try readI32(data, row_offset + delta_index * 4);            const offset = row_offset + @as(usize, self.word_delta_count) * 4 + (delta_index - @as(usize, self.word_delta_count)) * 2;            return try readI16(data, offset);        }        if (delta_index < self.word_delta_count) return try readI16(data, row_offset + delta_index * 2);        const offset = row_offset + @as(usize, self.word_delta_count) * 2 + (delta_index - @as(usize, self.word_delta_count));        return try readI8(data, offset);    }    fn regionIndexesOffset(self: ItemVariationData, region_index: usize) usize {        return self.region_indexes_offset + region_index * 2;    }};fn optionalDeltaSetIndexMap(data: []const u8, parent: Table, relative_offset: u32) FontError!?DeltaSetIndexMap {    if (relative_offset == 0) return null;    return try DeltaSetIndexMap.init(data, try variationChildTable(parent, relative_offset, 4));}pub fn variationChildTable(parent: Table, relative_offset: u32, min_len: usize) FontError!Table {    const offset = try variationChildOffset(parent, relative_offset, min_len);    return .{ .offset = offset, .len = parent.offset + parent.len - offset };}pub fn variationChildOffset(parent: Table, relative_offset: u32, min_len: usize) FontError!usize {    if (relative_offset == 0) return error.InvalidVariations;    if (relative_offset > std.math.maxInt(usize)) return error.InvalidVariations;    const relative: usize = @intCast(relative_offset);    if (relative > parent.len or min_len > parent.len - relative) return error.InvalidVariations;    return parent.offset + relative;}pub fn fixed16FromFloat(value: f32) FontError!i32 {    if (!std.math.isFinite(value)) return error.InvalidVariations;    const scaled = @as(f64, value) * 65536.0;    if (scaled > @as(f64, @floatFromInt(std.math.maxInt(i32)))) return error.InvalidVariations;    if (scaled < @as(f64, @floatFromInt(std.math.minInt(i32)))) return error.InvalidVariations;    const rounded = if (scaled >= 0) @floor(scaled + 0.5) else @ceil(scaled - 0.5);    return @intFromFloat(rounded);}pub fn normalizeVariationAxis(axis: VariationAxis, user_value: i32) i32 {    const clamped_user = std.math.clamp(user_value, axis.min_value, axis.max_value);    if (clamped_user < axis.default_value) {        const denominator = @as(i64, axis.default_value) - @as(i64, axis.min_value);        if (denominator == 0) return 0;        const numerator = (@as(i64, axis.default_value) - @as(i64, clamped_user)) * 65536;        return clampFixed16(-@divTrunc(numerator, denominator));    }    if (clamped_user > axis.default_value) {        const denominator = @as(i64, axis.max_value) - @as(i64, axis.default_value);        if (denominator == 0) return 0;        const numerator = (@as(i64, clamped_user) - @as(i64, axis.default_value)) * 65536;        return clampFixed16(@divTrunc(numerator, denominator));    }    return 0;}pub fn fixed16ToF2Dot14(value: i32) i16 {    const clamped = std.math.clamp(value, -65536, 65536);    return @intCast((clamped + 2) >> 2);}fn f2Dot14ToFixed16(value: i16) i32 {    return @as(i32, value) << 2;}fn clampFixed16(value: i64) i32 {    if (value > 65536) return 65536;    if (value < -65536) return -65536;    return @intCast(value);}const variationScalarOne: i32 = 65536;const variationScalarHalf: i64 = variationScalarOne / 2;fn roundVariationDelta(value: i64) i32 {    const rounded = @divFloor(value + variationScalarHalf, variationScalarOne);    return clampI32(rounded);}fn variationAxisScalar(start: i16, peak: i16, end: i16, instance: i16) i32 {    if (start > peak or peak > end) return variationScalarOne;    if (start < 0 and end > 0 and peak != 0) return variationScalarOne;    if (peak == 0) return variationScalarOne;    if (instance < start or instance > end) return 0;    if (instance == peak) return variationScalarOne;    if (instance < peak) {        const numerator = (@as(i64, instance) - @as(i64, start)) * variationScalarOne;        const denominator = @as(i64, peak) - @as(i64, start);        if (denominator <= 0) return 0;        return @intCast(@divTrunc(numerator, denominator));    }    const numerator = (@as(i64, end) - @as(i64, instance)) * variationScalarOne;    const denominator = @as(i64, end) - @as(i64, peak);    if (denominator <= 0) return 0;    return @intCast(@divTrunc(numerator, denominator));}pub fn clampDesignMetric(base: i32, delta: i32) i32 {    const value = @as(i64, base) + @as(i64, delta);    if (value <= 0) return 0;    if (value > std.math.maxInt(i32)) return std.math.maxInt(i32);    return @intCast(value);}pub fn clampI32(value: i64) i32 {    if (value > std.math.maxInt(i32)) return std.math.maxInt(i32);    if (value < std.math.minInt(i32)) return std.math.minInt(i32);    return @intCast(value);}fn avarMapAt(data: []const u8, records: usize, map_index: usize) FontError!AvarMap {    const offset = records + map_index * 4;    return .{        .from = f2Dot14ToFixed16(try readI16(data, offset)),        .to = f2Dot14ToFixed16(try readI16(data, offset + 2)),    };}fn avarHasRequiredMaps(data: []const u8, records: usize, count: u16) FontError!bool {    var has_min = false;    var has_default = false;    var has_max = false;    for (0..count) |map_index| {        const map_record = try avarMapAt(data, records, map_index);        if (map_record.from == -65536 and map_record.to == -65536) has_min = true;        if (map_record.from == 0 and map_record.to == 0) has_default = true;        if (map_record.from == 65536 and map_record.to == 65536) has_max = true;    }    return has_min and has_default and has_max;}test "item variation deltas round at use" {    try std.testing.expectEqual(@as(i32, 0), roundVariationDelta(variationScalarHalf - 1));    try std.testing.expectEqual(@as(i32, 1), roundVariationDelta(variationScalarHalf));    try std.testing.expectEqual(@as(i32, 2), roundVariationDelta(variationScalarOne + variationScalarHalf));    try std.testing.expectEqual(@as(i32, 0), roundVariationDelta(-variationScalarHalf));    try std.testing.expectEqual(@as(i32, -1), roundVariationDelta(-variationScalarHalf - 1));    try std.testing.expectEqual(@as(i32, -1), roundVariationDelta(-variationScalarOne - variationScalarHalf));    try std.testing.expectEqual(@as(i32, -2), roundVariationDelta(-variationScalarOne - variationScalarHalf - 1));}

Audit

Definitions29
Public names29
Members20
Version26.7.0
Revisiondaab053ee433