Skip to documentation
SLOP

tiny.filigree.font.cff

Reference tiny.filigree font cff

Defined in font.

API (2)

Actions

Public operations.

Types and contracts

Public types and contracts.

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

Source

Called byCallsprivate sourcelib.filigree.src.font.outlinecffGlyphAllocprivate sourcelib.filigree.src.font.cff.Fontinitprivate sourcelib.filigree.src.font.cff.Interpreterinitprivate sourcelib.filigree.src.font.cff.Interpreterrunfont.cffbuildGlyph
Static calls · unresolved targets: 1 · external targets: 1.

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

zig
const std = @import("std");const face_table = @import("face.zig");pub const Error = error{    InvalidFont,    MissingTable,    UnsupportedOutline,    OutOfMemory,};const max_stack = 64;const max_subr_depth = 16;const max_ops = 65536;pub fn buildGlyph(face: face_table.Face, glyph_id: u32, sink: anytype) Error!void {    if (glyph_id >= face.num_glyphs) return error.InvalidFont;    const font = try Font.init(face);    if (font.cid_keyed) return error.UnsupportedOutline;    if (glyph_id >= font.charstrings.count) return error.InvalidFont;    var interpreter = Interpreter.init(font);    const charstring = try font.charstrings.item(glyph_id);    switch (try interpreter.run(charstring, sink, 0)) {        .ended => {},        .returned, .exhausted => return error.InvalidFont,    }    try sink.close();}const Font = struct {    data: []const u8,    charstrings: Index,    global_subrs: Index,    local_subrs: ?Index = null,    cid_keyed: bool = false,    fn init(face: face_table.Face) Error!Font {        const data = face.tableSlice("CFF ") orelse return error.MissingTable;        if (data.len < 4) return error.InvalidFont;        if (data[0] != 1) return error.UnsupportedOutline;        const header_size: usize = data[2];        if (header_size < 4 or header_size > data.len) return error.InvalidFont;        const names = try Index.init(data, header_size);        if (names.count != 1) return error.InvalidFont;        const top_dicts = try Index.init(data, names.end);        if (top_dicts.count == 0) return error.InvalidFont;        const top = try parseTopDict(try top_dicts.item(0));        const strings = try Index.init(data, top_dicts.end);        const global_subrs = try Index.init(data, strings.end);        if (top.charstrings_offset == 0) return error.InvalidFont;        const charstrings = try Index.init(data, top.charstrings_offset);        if (charstrings.count != face.num_glyphs) return error.InvalidFont;        var local_subrs: ?Index = null;        if (top.private_size != 0) {            const private_start: usize = @intCast(top.private_offset);            const private_size: usize = @intCast(top.private_size);            if (private_start > data.len or private_size > data.len - private_start) return error.InvalidFont;            const private = try parsePrivateDict(data[private_start..][0..private_size]);            if (private.local_subrs_offset) |offset| {                const subrs_offset: usize = @intCast(offset);                if (subrs_offset > data.len - private_start) return error.InvalidFont;                local_subrs = try Index.init(data, private_start + subrs_offset);            }        }        return .{            .data = data,            .charstrings = charstrings,            .global_subrs = global_subrs,            .local_subrs = local_subrs,            .cid_keyed = top.cid_keyed,        };    }};const Index = struct {    data: []const u8,    count: u32 = 0,    off_size: u8 = 0,    offsets_offset: usize = 0,    object_offset: usize = 0,    end: usize = 0,    fn init(data: []const u8, offset: usize) Error!Index {        if (offset > data.len or data.len - offset < 2) return error.InvalidFont;        const count = try readU16(data, offset);        if (count == 0) {            return .{                .data = data,                .end = offset + 2,            };        }        if (data.len - offset < 3) return error.InvalidFont;        const off_size = data[offset + 2];        if (off_size == 0 or off_size > 4) return error.InvalidFont;        const count_usize: usize = count;        const offsets_offset = offset + 3;        const offset_bytes = (count_usize + 1) * @as(usize, off_size);        if (offsets_offset > data.len or offset_bytes > data.len - offsets_offset) return error.InvalidFont;        const object_offset = offsets_offset + offset_bytes;        const first = try readIndexOffset(data, offsets_offset, off_size, 0);        const last = try readIndexOffset(data, offsets_offset, off_size, count_usize);        if (first != 1 or last == 0) return error.InvalidFont;        const end = object_offset + @as(usize, @intCast(last - 1));        if (end > data.len) return error.InvalidFont;        return .{            .data = data,            .count = count,            .off_size = off_size,            .offsets_offset = offsets_offset,            .object_offset = object_offset,            .end = end,        };    }    fn item(self: Index, index: u32) Error![]const u8 {        if (index >= self.count) return error.InvalidFont;        const i: usize = @intCast(index);        const start_offset = try readIndexOffset(self.data, self.offsets_offset, self.off_size, i);        const end_offset = try readIndexOffset(self.data, self.offsets_offset, self.off_size, i + 1);        if (start_offset == 0 or end_offset < start_offset) return error.InvalidFont;        const start = self.object_offset + @as(usize, @intCast(start_offset - 1));        const end = self.object_offset + @as(usize, @intCast(end_offset - 1));        if (start > self.data.len or end > self.data.len or end < start) return error.InvalidFont;        return self.data[start..end];    }};const TopDict = struct {    charstrings_offset: u32 = 0,    private_size: u32 = 0,    private_offset: u32 = 0,    cid_keyed: bool = false,};const PrivateDict = struct {    local_subrs_offset: ?u32 = null,};fn parseTopDict(data: []const u8) Error!TopDict {    var result = TopDict{};    var stack = DictStack{};    var offset: usize = 0;    while (offset < data.len) {        const first = data[offset];        offset += 1;        if (isDictOperator(first)) {            if (first == 12) {                if (offset >= data.len) return error.InvalidFont;                const op = data[offset];                offset += 1;                switch (op) {                    30, 36, 37 => result.cid_keyed = true,                    else => {},                }            } else switch (first) {                17 => result.charstrings_offset = stack.lastU32() orelse return error.InvalidFont,                18 => {                    if (stack.len < 2) return error.InvalidFont;                    result.private_size = try stack.u32At(stack.len - 2);                    result.private_offset = try stack.u32At(stack.len - 1);                },                else => {},            }            stack.clear();            continue;        }        try stack.push(try readDictNumber(data, &offset, first));    }    return result;}fn parsePrivateDict(data: []const u8) Error!PrivateDict {    var result = PrivateDict{};    var stack = DictStack{};    var offset: usize = 0;    while (offset < data.len) {        const first = data[offset];        offset += 1;        if (isDictOperator(first)) {            if (first == 19) {                result.local_subrs_offset = stack.lastU32() orelse return error.InvalidFont;            } else if (first == 12) {                if (offset >= data.len) return error.InvalidFont;                offset += 1;            }            stack.clear();            continue;        }        try stack.push(try readDictNumber(data, &offset, first));    }    return result;}const DictStack = struct {    values: [max_stack]i32 = undefined,    len: usize = 0,    fn push(self: *DictStack, value: i32) Error!void {        if (self.len >= self.values.len) return error.InvalidFont;        self.values[self.len] = value;        self.len += 1;    }    fn clear(self: *DictStack) void {        self.len = 0;    }    fn lastU32(self: *const DictStack) ?u32 {        if (self.len == 0) return null;        return std.math.cast(u32, self.values[self.len - 1]);    }    fn u32At(self: *const DictStack, index: usize) Error!u32 {        if (index >= self.len) return error.InvalidFont;        return std.math.cast(u32, self.values[index]) orelse error.InvalidFont;    }};const RunResult = enum {    exhausted,    returned,    ended,};const OperatorResult = enum {    none,    ended,    returned,};const Interpreter = struct {    font: Font,    stack: [max_stack]i32 = undefined,    stack_len: usize = 0,    x: i32 = 0,    y: i32 = 0,    stem_count: usize = 0,    width_seen: bool = false,    op_count: usize = 0,    fn init(font: Font) Interpreter {        return .{ .font = font };    }    fn run(self: *Interpreter, data: []const u8, sink: anytype, depth: usize) Error!RunResult {        if (depth > max_subr_depth) return error.InvalidFont;        var offset: usize = 0;        while (offset < data.len) {            self.op_count += 1;            if (self.op_count > max_ops) return error.InvalidFont;            const first = data[offset];            offset += 1;            if (first == 12) {                if (offset >= data.len) return error.InvalidFont;                const op = data[offset];                offset += 1;                try self.escaped(op, sink);                continue;            }            if (first == 28 or first > 31) {                try self.push(try readCharNumber(data, &offset, first));                continue;            }            if (first <= 31) {                switch (try self.operator(first, data, &offset, sink, depth)) {                    .ended => return .ended,                    .returned => return .returned,                    .none => {},                }                continue;            }        }        return .exhausted;    }    fn operator(self: *Interpreter, op: u8, data: []const u8, offset: *usize, sink: anytype, depth: usize) Error!OperatorResult {        switch (op) {            1, 18, 3, 23 => self.consumeStems(),            19, 20 => try self.consumeMask(data, offset),            4 => try self.vmoveTo(sink),            5 => try self.rlineTo(sink),            6 => try self.alternatingLineTo(sink, true),            7 => try self.alternatingLineTo(sink, false),            8 => try self.rrcurveTo(sink),            10 => if (try self.callSubr(sink, depth)) return .ended,            11 => return .returned,            14 => {                self.clear();                try sink.close();                return .ended;            },            21 => try self.rmoveTo(sink),            22 => try self.hmoveTo(sink),            24 => try self.rcurveLine(sink),            25 => try self.rlineCurve(sink),            26 => try self.vvcurveTo(sink),            27 => try self.hhcurveTo(sink),            29 => if (try self.callGlobalSubr(sink, depth)) return .ended,            30 => try self.alternatingCurveTo(sink, false),            31 => try self.alternatingCurveTo(sink, true),            else => return error.UnsupportedOutline,        }        return .none;    }    fn escaped(self: *Interpreter, op: u8, sink: anytype) Error!void {        switch (op) {            34 => try self.hflex(sink),            35 => try self.flex(sink),            36 => try self.hflex1(sink),            37 => try self.flex1(sink),            else => return error.UnsupportedOutline,        }    }    fn push(self: *Interpreter, value: i32) Error!void {        if (self.stack_len >= self.stack.len) return error.InvalidFont;        self.stack[self.stack_len] = value;        self.stack_len += 1;    }    fn pop(self: *Interpreter) Error!i32 {        if (self.stack_len == 0) return error.InvalidFont;        self.stack_len -= 1;        return self.stack[self.stack_len];    }    fn clear(self: *Interpreter) void {        self.stack_len = 0;    }    fn noteWidth(self: *Interpreter, expected_operands: usize) Error!void {        if (!self.width_seen and self.stack_len > expected_operands) {            try self.dropFirst();        }        self.width_seen = true;    }    fn dropFirst(self: *Interpreter) Error!void {        if (self.stack_len == 0) return error.InvalidFont;        std.mem.copyForwards(i32, self.stack[0 .. self.stack_len - 1], self.stack[1..self.stack_len]);        self.stack_len -= 1;    }    fn consumeStems(self: *Interpreter) void {        var len = self.stack_len;        if (!self.width_seen and len % 2 == 1) {            std.mem.copyForwards(i32, self.stack[0 .. len - 1], self.stack[1..len]);            len -= 1;        }        self.width_seen = true;        self.stem_count += len / 2;        self.clear();    }    fn consumeMask(self: *Interpreter, data: []const u8, offset: *usize) Error!void {        if (self.stack_len > 0) self.consumeStems();        const mask_len = (self.stem_count + 7) / 8;        if (mask_len > data.len - offset.*) return error.InvalidFont;        offset.* += mask_len;        self.clear();    }    fn rmoveTo(self: *Interpreter, sink: anytype) Error!void {        try self.noteWidth(2);        if (self.stack_len != 2) return error.InvalidFont;        const dx = self.stack[0];        const dy = self.stack[1];        self.clear();        try self.moveRel(sink, dx, dy);    }    fn hmoveTo(self: *Interpreter, sink: anytype) Error!void {        try self.noteWidth(1);        if (self.stack_len != 1) return error.InvalidFont;        const dx = self.stack[0];        self.clear();        try self.moveRel(sink, dx, 0);    }    fn vmoveTo(self: *Interpreter, sink: anytype) Error!void {        try self.noteWidth(1);        if (self.stack_len != 1) return error.InvalidFont;        const dy = self.stack[0];        self.clear();        try self.moveRel(sink, 0, dy);    }    fn rlineTo(self: *Interpreter, sink: anytype) Error!void {        if (self.stack_len == 0 or self.stack_len % 2 != 0) return error.InvalidFont;        var index: usize = 0;        while (index < self.stack_len) : (index += 2) {            try self.lineRel(sink, self.stack[index], self.stack[index + 1]);        }        self.clear();    }    fn alternatingLineTo(self: *Interpreter, sink: anytype, horizontal_first: bool) Error!void {        if (self.stack_len == 0) return error.InvalidFont;        var horizontal = horizontal_first;        for (self.stack[0..self.stack_len]) |value| {            if (horizontal) {                try self.lineRel(sink, value, 0);            } else {                try self.lineRel(sink, 0, value);            }            horizontal = !horizontal;        }        self.clear();    }    fn rrcurveTo(self: *Interpreter, sink: anytype) Error!void {        if (self.stack_len == 0 or self.stack_len % 6 != 0) return error.InvalidFont;        var index: usize = 0;        while (index < self.stack_len) : (index += 6) {            try self.curveRel(sink, self.stack[index], self.stack[index + 1], self.stack[index + 2], self.stack[index + 3], self.stack[index + 4], self.stack[index + 5]);        }        self.clear();    }    fn rcurveLine(self: *Interpreter, sink: anytype) Error!void {        if (self.stack_len < 8 or (self.stack_len - 2) % 6 != 0) return error.InvalidFont;        var index: usize = 0;        while (index + 2 < self.stack_len) : (index += 6) {            try self.curveRel(sink, self.stack[index], self.stack[index + 1], self.stack[index + 2], self.stack[index + 3], self.stack[index + 4], self.stack[index + 5]);        }        try self.lineRel(sink, self.stack[self.stack_len - 2], self.stack[self.stack_len - 1]);        self.clear();    }    fn rlineCurve(self: *Interpreter, sink: anytype) Error!void {        if (self.stack_len < 8 or (self.stack_len - 6) % 2 != 0) return error.InvalidFont;        var index: usize = 0;        while (index + 6 < self.stack_len) : (index += 2) {            try self.lineRel(sink, self.stack[index], self.stack[index + 1]);        }        try self.curveRel(sink, self.stack[index], self.stack[index + 1], self.stack[index + 2], self.stack[index + 3], self.stack[index + 4], self.stack[index + 5]);        self.clear();    }    fn hhcurveTo(self: *Interpreter, sink: anytype) Error!void {        if (self.stack_len < 4) return error.InvalidFont;        if (self.stack_len % 4 != 0 and self.stack_len % 4 != 1) return error.InvalidFont;        var index: usize = 0;        var dy1: i32 = 0;        if (self.stack_len % 4 == 1) {            dy1 = self.stack[0];            index = 1;        }        while (index < self.stack_len) : (index += 4) {            try self.curveRel(sink, self.stack[index], dy1, self.stack[index + 1], self.stack[index + 2], self.stack[index + 3], 0);            dy1 = 0;        }        self.clear();    }    fn vvcurveTo(self: *Interpreter, sink: anytype) Error!void {        if (self.stack_len < 4) return error.InvalidFont;        if (self.stack_len % 4 != 0 and self.stack_len % 4 != 1) return error.InvalidFont;        var index: usize = 0;        var dx1: i32 = 0;        if (self.stack_len % 4 == 1) {            dx1 = self.stack[0];            index = 1;        }        while (index < self.stack_len) : (index += 4) {            try self.curveRel(sink, dx1, self.stack[index], self.stack[index + 1], self.stack[index + 2], 0, self.stack[index + 3]);            dx1 = 0;        }        self.clear();    }    fn alternatingCurveTo(self: *Interpreter, sink: anytype, horizontal_first: bool) Error!void {        if (self.stack_len < 4) return error.InvalidFont;        var index: usize = 0;        var horizontal = horizontal_first;        while (index < self.stack_len) {            const remaining = self.stack_len - index;            if (remaining != 4 and remaining != 5 and remaining < 8) return error.InvalidFont;            if (horizontal) {                const dx1 = self.stack[index];                const dx2 = self.stack[index + 1];                const dy2 = self.stack[index + 2];                const dy3 = self.stack[index + 3];                const dx3 = if (remaining == 5) self.stack[index + 4] else 0;                try self.curveRel(sink, dx1, 0, dx2, dy2, dx3, dy3);                index += if (remaining == 5) 5 else 4;            } else {                const dy1 = self.stack[index];                const dx2 = self.stack[index + 1];                const dy2 = self.stack[index + 2];                const dx3 = self.stack[index + 3];                const dy3 = if (remaining == 5) self.stack[index + 4] else 0;                try self.curveRel(sink, 0, dy1, dx2, dy2, dx3, dy3);                index += if (remaining == 5) 5 else 4;            }            horizontal = !horizontal;        }        self.clear();    }    fn hflex(self: *Interpreter, sink: anytype) Error!void {        if (self.stack_len != 7) return error.InvalidFont;        const a = self.stack[0..7];        try self.curveRel(sink, a[0], 0, a[1], a[2], a[3], 0);        try self.curveRel(sink, a[4], 0, a[5], -a[2], a[6], 0);        self.clear();    }    fn flex(self: *Interpreter, sink: anytype) Error!void {        if (self.stack_len != 13) return error.InvalidFont;        const a = self.stack[0..13];        try self.curveRel(sink, a[0], a[1], a[2], a[3], a[4], a[5]);        try self.curveRel(sink, a[6], a[7], a[8], a[9], a[10], a[11]);        self.clear();    }    fn hflex1(self: *Interpreter, sink: anytype) Error!void {        if (self.stack_len != 9) return error.InvalidFont;        const a = self.stack[0..9];        try self.curveRel(sink, a[0], a[1], a[2], a[3], a[4], 0);        try self.curveRel(sink, a[5], 0, a[6], a[7], a[8], -(a[1] + a[3] + a[7]));        self.clear();    }    fn flex1(self: *Interpreter, sink: anytype) Error!void {        if (self.stack_len != 11) return error.InvalidFont;        const a = self.stack[0..11];        const dx_sum = a[0] + a[2] + a[4] + a[6] + a[8];        const dy_sum = a[1] + a[3] + a[5] + a[7] + a[9];        const dx6 = if (@abs(dx_sum) > @abs(dy_sum)) a[10] else -dx_sum;        const dy6 = if (@abs(dx_sum) > @abs(dy_sum)) -dy_sum else a[10];        try self.curveRel(sink, a[0], a[1], a[2], a[3], a[4], a[5]);        try self.curveRel(sink, a[6], a[7], a[8], a[9], dx6, dy6);        self.clear();    }    fn callSubr(self: *Interpreter, sink: anytype, depth: usize) Error!bool {        const subrs = self.font.local_subrs orelse return error.InvalidFont;        return try self.callIndexSubr(subrs, sink, depth);    }    fn callGlobalSubr(self: *Interpreter, sink: anytype, depth: usize) Error!bool {        return try self.callIndexSubr(self.font.global_subrs, sink, depth);    }    fn callIndexSubr(self: *Interpreter, subrs: Index, sink: anytype, depth: usize) Error!bool {        const raw = try self.pop();        const biased = raw + subrBias(subrs.count);        if (biased < 0) return error.InvalidFont;        const index: u32 = @intCast(biased);        if (index >= subrs.count) return error.InvalidFont;        const subr = try subrs.item(index);        return switch (try self.run(subr, sink, depth + 1)) {            .ended => true,            .returned => false,            .exhausted => error.InvalidFont,        };    }    fn moveRel(self: *Interpreter, sink: anytype, dx: i32, dy: i32) Error!void {        self.x += dx;        self.y += dy;        try sink.moveTo(self.x, self.y);    }    fn lineRel(self: *Interpreter, sink: anytype, dx: i32, dy: i32) Error!void {        self.x += dx;        self.y += dy;        try sink.lineTo(self.x, self.y);    }    fn curveRel(self: *Interpreter, sink: anytype, dx1: i32, dy1: i32, dx2: i32, dy2: i32, dx3: i32, dy3: i32) Error!void {        const x1 = self.x + dx1;        const y1 = self.y + dy1;        const x2 = x1 + dx2;        const y2 = y1 + dy2;        self.x = x2 + dx3;        self.y = y2 + dy3;        try sink.curveTo(x1, y1, x2, y2, self.x, self.y);    }};fn subrBias(count: u32) i32 {    if (count < 1240) return 107;    if (count < 33900) return 1131;    return 32768;}fn isDictOperator(byte: u8) bool {    return byte <= 21 and byte != 28;}fn readDictNumber(data: []const u8, offset: *usize, first: u8) Error!i32 {    return switch (first) {        28 => value: {            const value = try readI16(data, offset.*);            offset.* += 2;            break :value value;        },        29 => value: {            const value = try readI32(data, offset.*);            offset.* += 4;            break :value value;        },        30 => value: {            try skipReal(data, offset);            break :value 0;        },        32...246 => @as(i32, first) - 139,        247...250 => value: {            if (offset.* >= data.len) return error.InvalidFont;            const b1 = data[offset.*];            offset.* += 1;            break :value (@as(i32, first) - 247) * 256 + @as(i32, b1) + 108;        },        251...254 => value: {            if (offset.* >= data.len) return error.InvalidFont;            const b1 = data[offset.*];            offset.* += 1;            break :value -((@as(i32, first) - 251) * 256) - @as(i32, b1) - 108;        },        255 => value: {            const value = try readI32(data, offset.*);            offset.* += 4;            break :value value;        },        else => error.InvalidFont,    };}fn readCharNumber(data: []const u8, offset: *usize, first: u8) Error!i32 {    return switch (first) {        28 => value: {            const value = try readI16(data, offset.*);            offset.* += 2;            break :value value;        },        32...246 => @as(i32, first) - 139,        247...250 => value: {            if (offset.* >= data.len) return error.InvalidFont;            const b1 = data[offset.*];            offset.* += 1;            break :value (@as(i32, first) - 247) * 256 + @as(i32, b1) + 108;        },        251...254 => value: {            if (offset.* >= data.len) return error.InvalidFont;            const b1 = data[offset.*];            offset.* += 1;            break :value -((@as(i32, first) - 251) * 256) - @as(i32, b1) - 108;        },        255 => value: {            const value = try readI32(data, offset.*);            offset.* += 4;            break :value value;        },        else => error.InvalidFont,    };}fn skipReal(data: []const u8, offset: *usize) Error!void {    while (offset.* < data.len) {        const byte = data[offset.*];        offset.* += 1;        if ((byte >> 4) == 0xf or (byte & 0xf) == 0xf) return;    }    return error.InvalidFont;}fn readIndexOffset(data: []const u8, offsets_offset: usize, off_size: u8, index: usize) Error!u32 {    const offset = offsets_offset + index * @as(usize, off_size);    if (offset > data.len or @as(usize, off_size) > data.len - offset) return error.InvalidFont;    var value: u32 = 0;    var i: usize = 0;    while (i < off_size) : (i += 1) {        value = (value << 8) | data[offset + i];    }    return value;}fn readU16(data: []const u8, offset: usize) Error!u16 {    if (offset + 2 > data.len) return error.InvalidFont;    return std.mem.readInt(u16, data[offset..][0..2], .big);}fn readI16(data: []const u8, offset: usize) Error!i16 {    return @bitCast(try readU16(data, offset));}fn readI32(data: []const u8, offset: usize) Error!i32 {    if (offset + 4 > data.len) return error.InvalidFont;    return std.mem.readInt(i32, data[offset..][0..4], .big);}

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

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

Audit

Definitions3
Public names3
Members4
Version26.7.0
Revisiondaab053ee433