tiny.filigree.layout.coverage
Defined in layout.
API (3)
Types and contracts
Public types and contracts.
Source
Source: lib/filigree/src/layout/coverage.zig
zig
const std = @import("std");const binary = @import("binary.zig");const LayoutError = binary.LayoutError;const hasBytes = binary.hasBytes;const readU16 = binary.readU16;pub const Coverage = union(enum) { format_1: CoverageFormat1, format_2: CoverageFormat2, pub fn init(data: []const u8, offset: usize) LayoutError!Coverage { if (!hasBytes(data, offset, 2)) return error.InvalidLayout; return switch (try readU16(data, offset)) { 1 => .{ .format_1 = try CoverageFormat1.init(data, offset) }, 2 => .{ .format_2 = try CoverageFormat2.init(data, offset) }, else => error.UnsupportedCoverage, }; } pub fn index(self: Coverage, data: []const u8, glyph_id: u32) LayoutError!?u16 { return switch (self) { .format_1 => |format| format.index(data, glyph_id), .format_2 => |format| format.index(data, glyph_id), }; }};pub const CoverageFormat1 = struct { glyph_array_offset: usize, glyph_count: u16, fn init(data: []const u8, offset: usize) LayoutError!CoverageFormat1 { if (!hasBytes(data, offset, 4)) return error.InvalidLayout; const glyph_count = try readU16(data, offset + 2); const array_offset = offset + 4; const array_len = @as(usize, glyph_count) * 2; if (!hasBytes(data, array_offset, array_len)) return error.InvalidLayout; var previous: ?u16 = null; for (0..glyph_count) |i| { const glyph = try readU16(data, array_offset + i * 2); if (previous) |seen| { if (glyph <= seen) return error.InvalidLayout; } previous = glyph; } return .{ .glyph_array_offset = array_offset, .glyph_count = glyph_count, }; } fn index(self: CoverageFormat1, data: []const u8, glyph_id: u32) LayoutError!?u16 { if (glyph_id > std.math.maxInt(u16)) return null; const glyph: u16 = @intCast(glyph_id); var left: usize = 0; var right: usize = self.glyph_count; while (left < right) { const mid = left + (right - left) / 2; const candidate = try readU16(data, self.glyph_array_offset + mid * 2); if (glyph < candidate) { right = mid; } else if (glyph > candidate) { left = mid + 1; } else { return @intCast(mid); } } return null; }};pub const CoverageFormat2 = struct { range_array_offset: usize, range_count: u16, fn init(data: []const u8, offset: usize) LayoutError!CoverageFormat2 { if (!hasBytes(data, offset, 4)) return error.InvalidLayout; const range_count = try readU16(data, offset + 2); const array_offset = offset + 4; const array_len = @as(usize, range_count) * 6; if (!hasBytes(data, array_offset, array_len)) return error.InvalidLayout; var previous_end: ?u16 = null; for (0..range_count) |i| { const record = array_offset + i * 6; const start = try readU16(data, record); const end = try readU16(data, record + 2); if (start > end) return error.InvalidLayout; if (previous_end) |seen| { if (start <= seen) return error.InvalidLayout; } previous_end = end; } return .{ .range_array_offset = array_offset, .range_count = range_count, }; } fn index(self: CoverageFormat2, data: []const u8, glyph_id: u32) LayoutError!?u16 { if (glyph_id > std.math.maxInt(u16)) return null; const glyph: u16 = @intCast(glyph_id); var left: usize = 0; var right: usize = self.range_count; while (left < right) { const mid = left + (right - left) / 2; const record = self.range_array_offset + mid * 6; const start = try readU16(data, record); const end = try readU16(data, record + 2); if (glyph < start) { right = mid; } else if (glyph > end) { left = mid + 1; } else { const start_index = try readU16(data, record + 4); const delta = glyph - start; if (start_index > std.math.maxInt(u16) - delta) return error.InvalidLayout; return start_index + delta; } } return null; }};test "Coverage format 1 maps sorted glyph array to indexes" { const data = [_]u8{ 0, 1, 0, 3, 0, 5, 0, 9, 0, 20, }; const coverage = try Coverage.init(&data, 0); try std.testing.expectEqual(@as(?u16, 0), try coverage.index(&data, 5)); try std.testing.expectEqual(@as(?u16, 1), try coverage.index(&data, 9)); try std.testing.expectEqual(@as(?u16, 2), try coverage.index(&data, 20)); try std.testing.expectEqual(@as(?u16, null), try coverage.index(&data, 6)); try std.testing.expectEqual(@as(?u16, null), try coverage.index(&data, 0x1_0000));}test "Coverage format 1 rejects unsorted glyph array" { const data = [_]u8{ 0, 1, 0, 2, 0, 7, 0, 7, }; try std.testing.expectError(error.InvalidLayout, Coverage.init(&data, 0));}test "Coverage format 2 maps glyph ranges to indexes" { const data = [_]u8{ 0, 2, 0, 2, 0, 10, 0, 12, 0, 0, 0, 20, 0, 21, 0, 3, }; const coverage = try Coverage.init(&data, 0); try std.testing.expectEqual(@as(?u16, 0), try coverage.index(&data, 10)); try std.testing.expectEqual(@as(?u16, 2), try coverage.index(&data, 12)); try std.testing.expectEqual(@as(?u16, 3), try coverage.index(&data, 20)); try std.testing.expectEqual(@as(?u16, 4), try coverage.index(&data, 21)); try std.testing.expectEqual(@as(?u16, null), try coverage.index(&data, 13));}test "Coverage format 2 rejects overlapping ranges" { const data = [_]u8{ 0, 2, 0, 2, 0, 10, 0, 12, 0, 0, 0, 12, 0, 14, 0, 3, }; try std.testing.expectError(error.InvalidLayout, Coverage.init(&data, 0));}test "Coverage honors nonzero table offsets" { const data = [_]u8{ 0xaa, 0xbb, 0, 1, 0, 1, 0, 42, }; const coverage = try Coverage.init(&data, 2); try std.testing.expectEqual(@as(?u16, 0), try coverage.index(&data, 42));}Source: lib/filigree/src/layout/root.zig:3
zig
pub const coverage = @import("coverage.zig");Audit
| Definitions | 3 |
|---|---|
| Public names | 5 |
| Members | 4 |
| Version | 26.7.0 |
| Revision | daab053ee433 |