freetype: initial import @ 4e2b158
Signed-off-by: Stephen Gutekanst <stephen@hexops.com>
This commit is contained in:
parent
0d2675507d
commit
b50dade2fd
20 changed files with 2252 additions and 0 deletions
54
freetype/src/Bitmap.zig
Normal file
54
freetype/src/Bitmap.zig
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
const std = @import("std");
|
||||
const c = @import("c.zig");
|
||||
const Error = @import("error.zig").Error;
|
||||
const convertError = @import("error.zig").convertError;
|
||||
|
||||
const Bitmap = @This();
|
||||
|
||||
pub const PixelMode = enum {
|
||||
none,
|
||||
mono,
|
||||
gray,
|
||||
gray2,
|
||||
gray4,
|
||||
lcd,
|
||||
lcd_v,
|
||||
bgra,
|
||||
};
|
||||
|
||||
handle: c.FT_Bitmap,
|
||||
|
||||
pub fn init(handle: c.FT_Bitmap) Bitmap {
|
||||
return Bitmap{ .handle = handle };
|
||||
}
|
||||
|
||||
pub fn width(self: Bitmap) u32 {
|
||||
return self.handle.width;
|
||||
}
|
||||
|
||||
pub fn pitch(self: Bitmap) i32 {
|
||||
return self.handle.pitch;
|
||||
}
|
||||
|
||||
pub fn rows(self: Bitmap) u32 {
|
||||
return self.handle.rows;
|
||||
}
|
||||
|
||||
pub fn pixelMode(self: Bitmap) PixelMode {
|
||||
return switch (self.handle.pixel_mode) {
|
||||
c.FT_PIXEL_MODE_NONE => .none,
|
||||
c.FT_PIXEL_MODE_MONO => .mono,
|
||||
c.FT_PIXEL_MODE_GRAY => .gray,
|
||||
c.FT_PIXEL_MODE_GRAY2 => .gray2,
|
||||
c.FT_PIXEL_MODE_GRAY4 => .gray4,
|
||||
c.FT_PIXEL_MODE_LCD => .lcd,
|
||||
c.FT_PIXEL_MODE_LCD_V => .lcd_v,
|
||||
c.FT_PIXEL_MODE_BGRA => .bgra,
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn buffer(self: Bitmap) []u8 {
|
||||
const buffer_size = std.math.absCast(self.pitch()) * self.rows();
|
||||
return self.handle.buffer[0..buffer_size];
|
||||
}
|
||||
35
freetype/src/BitmapGlyph.zig
Normal file
35
freetype/src/BitmapGlyph.zig
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
const std = @import("std");
|
||||
const c = @import("c.zig");
|
||||
const Bitmap = @import("Bitmap.zig");
|
||||
const Error = @import("error.zig").Error;
|
||||
const convertError = @import("error.zig").convertError;
|
||||
|
||||
const BitmapGlyph = @This();
|
||||
|
||||
handle: c.FT_BitmapGlyph,
|
||||
|
||||
pub fn init(handle: c.FT_BitmapGlyph) BitmapGlyph {
|
||||
return BitmapGlyph{ .handle = handle };
|
||||
}
|
||||
|
||||
pub fn deinit(self: BitmapGlyph) void {
|
||||
c.FT_Done_Glyph(@ptrCast(c.FT_Glyph, self.handle));
|
||||
}
|
||||
|
||||
pub fn clone(self: BitmapGlyph) Error!BitmapGlyph {
|
||||
var res = std.mem.zeroes(c.FT_Glyph);
|
||||
try convertError(c.FT_Glyph_Copy(@ptrCast(c.FT_Glyph, self.handle), &res));
|
||||
return BitmapGlyph.init(@ptrCast(c.FT_BitmapGlyph, res));
|
||||
}
|
||||
|
||||
pub fn left(self: BitmapGlyph) i32 {
|
||||
return self.handle.*.left;
|
||||
}
|
||||
|
||||
pub fn top(self: BitmapGlyph) i32 {
|
||||
return self.handle.*.top;
|
||||
}
|
||||
|
||||
pub fn bitmap(self: BitmapGlyph) Bitmap {
|
||||
return Bitmap.init(self.handle.*.bitmap);
|
||||
}
|
||||
267
freetype/src/Face.zig
Normal file
267
freetype/src/Face.zig
Normal file
|
|
@ -0,0 +1,267 @@
|
|||
const std = @import("std");
|
||||
const c = @import("c.zig");
|
||||
const types = @import("types.zig");
|
||||
const GlyphSlot = @import("GlyphSlot.zig");
|
||||
const Library = @import("Library.zig");
|
||||
const Error = @import("error.zig").Error;
|
||||
const convertError = @import("error.zig").convertError;
|
||||
const utils = @import("utils.zig");
|
||||
|
||||
const Face = @This();
|
||||
|
||||
pub const SizeMetrics = c.FT_Size_Metrics;
|
||||
pub const KerningMode = enum(u2) {
|
||||
default = c.FT_KERNING_DEFAULT,
|
||||
unfitted = c.FT_KERNING_UNFITTED,
|
||||
unscaled = c.FT_KERNING_UNSCALED,
|
||||
};
|
||||
pub const LoadFlags = packed struct {
|
||||
no_scale: bool = false,
|
||||
no_hinting: bool = false,
|
||||
render: bool = false,
|
||||
no_bitmap: bool = false,
|
||||
vertical_layout: bool = false,
|
||||
force_autohint: bool = false,
|
||||
crop_bitmap: bool = false,
|
||||
pedantic: bool = false,
|
||||
ignore_global_advance_with: bool = false,
|
||||
no_recurse: bool = false,
|
||||
ignore_transform: bool = false,
|
||||
monochrome: bool = false,
|
||||
linear_design: bool = false,
|
||||
no_autohint: bool = false,
|
||||
target_normal: bool = false,
|
||||
target_light: bool = false,
|
||||
target_mono: bool = false,
|
||||
target_lcd: bool = false,
|
||||
target_lcd_v: bool = false,
|
||||
color: bool = false,
|
||||
|
||||
pub const Flag = enum(u21) {
|
||||
no_scale = c.FT_LOAD_NO_SCALE,
|
||||
no_hinting = c.FT_LOAD_NO_HINTING,
|
||||
render = c.FT_LOAD_RENDER,
|
||||
no_bitmap = c.FT_LOAD_NO_BITMAP,
|
||||
vertical_layout = c.FT_LOAD_VERTICAL_LAYOUT,
|
||||
force_autohint = c.FT_LOAD_FORCE_AUTOHINT,
|
||||
crop_bitmap = c.FT_LOAD_CROP_BITMAP,
|
||||
pedantic = c.FT_LOAD_PEDANTIC,
|
||||
ignore_global_advance_with = c.FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH,
|
||||
no_recurse = c.FT_LOAD_NO_RECURSE,
|
||||
ignore_transform = c.FT_LOAD_IGNORE_TRANSFORM,
|
||||
monochrome = c.FT_LOAD_MONOCHROME,
|
||||
linear_design = c.FT_LOAD_LINEAR_DESIGN,
|
||||
no_autohint = c.FT_LOAD_NO_AUTOHINT,
|
||||
target_normal = c.FT_LOAD_TARGET_NORMAL,
|
||||
target_light = c.FT_LOAD_TARGET_LIGHT,
|
||||
target_mono = c.FT_LOAD_TARGET_MONO,
|
||||
target_lcd = c.FT_LOAD_TARGET_LCD,
|
||||
target_lcd_v = c.FT_LOAD_TARGET_LCD_V,
|
||||
color = c.FT_LOAD_COLOR,
|
||||
};
|
||||
|
||||
pub fn toBitFields(flags: LoadFlags) u21 {
|
||||
return utils.structToBitFields(u21, Flag, flags);
|
||||
}
|
||||
};
|
||||
pub const StyleFlags = packed struct {
|
||||
bold: bool = false,
|
||||
italic: bool = false,
|
||||
|
||||
pub const Flag = enum(u2) {
|
||||
bold = c.FT_STYLE_FLAG_BOLD,
|
||||
italic = c.FT_STYLE_FLAG_ITALIC,
|
||||
};
|
||||
|
||||
pub fn toBitFields(flags: StyleFlags) u2 {
|
||||
return utils.structToBitFields(u2, StyleFlags, Flag, flags);
|
||||
}
|
||||
};
|
||||
|
||||
handle: c.FT_Face,
|
||||
glyph: GlyphSlot,
|
||||
|
||||
pub fn init(handle: c.FT_Face) Face {
|
||||
return Face{
|
||||
.handle = handle,
|
||||
.glyph = GlyphSlot.init(handle.*.glyph),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn deinit(self: Face) void {
|
||||
convertError(c.FT_Done_Face(self.handle)) catch |err| {
|
||||
std.log.err("mach/freetype: Failed to destroy Face: {}", .{err});
|
||||
};
|
||||
}
|
||||
|
||||
pub fn attachFile(self: Face, path: []const u8) Error!void {
|
||||
return self.attachStream(.{
|
||||
.flags = .{ .path = true },
|
||||
.data = .{ .path = path },
|
||||
});
|
||||
}
|
||||
|
||||
pub fn attachMemory(self: Face, bytes: []const u8) Error!void {
|
||||
return self.attachStream(.{
|
||||
.flags = .{ .memory = true },
|
||||
.data = .{ .memory = bytes },
|
||||
});
|
||||
}
|
||||
|
||||
pub fn attachStream(self: Face, args: types.OpenArgs) Error!void {
|
||||
return convertError(c.FT_Attach_Stream(self.handle, &args.toCInterface()));
|
||||
}
|
||||
|
||||
pub fn setCharSize(self: Face, pt_width: i32, pt_height: i32, horz_resolution: u16, vert_resolution: u16) Error!void {
|
||||
return convertError(c.FT_Set_Char_Size(self.handle, pt_width, pt_height, horz_resolution, vert_resolution));
|
||||
}
|
||||
|
||||
pub fn setPixelSizes(self: Face, pixel_width: u32, pixel_height: u32) Error!void {
|
||||
return convertError(c.FT_Set_Pixel_Sizes(self.handle, pixel_width, pixel_height));
|
||||
}
|
||||
|
||||
pub fn loadGlyph(self: Face, index: u32, flags: LoadFlags) Error!void {
|
||||
return convertError(c.FT_Load_Glyph(self.handle, index, flags.toBitFields()));
|
||||
}
|
||||
|
||||
pub fn loadChar(self: Face, char: u32, flags: LoadFlags) Error!void {
|
||||
return convertError(c.FT_Load_Char(self.handle, char, flags.toBitFields()));
|
||||
}
|
||||
|
||||
pub fn setTransform(self: Face, matrix: ?types.Matrix, delta: ?types.Vector) Error!void {
|
||||
var m = matrix orelse std.mem.zeroes(types.Matrix);
|
||||
var d = delta orelse std.mem.zeroes(types.Vector);
|
||||
return c.FT_Set_Transform(self.handle, &m, &d);
|
||||
}
|
||||
|
||||
pub fn getCharIndex(self: Face, index: u32) ?u32 {
|
||||
const i = c.FT_Get_Char_Index(self.handle, index);
|
||||
return if (i == 0) null else i;
|
||||
}
|
||||
|
||||
pub fn getKerning(self: Face, left_char_index: u32, right_char_index: u32, mode: KerningMode) Error!types.Vector {
|
||||
var vec = std.mem.zeroes(types.Vector);
|
||||
try convertError(c.FT_Get_Kerning(self.handle, left_char_index, right_char_index, @enumToInt(mode), &vec));
|
||||
return vec;
|
||||
}
|
||||
|
||||
pub fn hasHorizontal(self: Face) bool {
|
||||
return c.FT_HAS_HORIZONTAL(self.handle);
|
||||
}
|
||||
|
||||
pub fn hasVertical(self: Face) bool {
|
||||
return c.FT_HAS_VERTICAL(self.handle);
|
||||
}
|
||||
|
||||
pub fn hasKerning(self: Face) bool {
|
||||
return c.FT_HAS_KERNING(self.handle);
|
||||
}
|
||||
|
||||
pub fn hasFixedSizes(self: Face) bool {
|
||||
return c.FT_HAS_FIXED_SIZES(self.handle);
|
||||
}
|
||||
|
||||
pub fn hasGlyphNames(self: Face) bool {
|
||||
return c.FT_HAS_GLYPH_NAMES(self.handle);
|
||||
}
|
||||
|
||||
pub fn hasColor(self: Face) bool {
|
||||
return c.FT_HAS_COLOR(self.handle);
|
||||
}
|
||||
|
||||
pub fn isScalable(self: Face) bool {
|
||||
return c.FT_IS_SCALABLE(self.handle);
|
||||
}
|
||||
|
||||
pub fn isSfnt(self: Face) bool {
|
||||
return c.FT_IS_SFNT(self.handle);
|
||||
}
|
||||
|
||||
pub fn isFixedWidth(self: Face) bool {
|
||||
return c.FT_IS_FIXED_WIDTH(self.handle);
|
||||
}
|
||||
|
||||
pub fn isCidKeyed(self: Face) bool {
|
||||
return c.FT_IS_CID_KEYED(self.handle);
|
||||
}
|
||||
|
||||
pub fn isTricky(self: Face) bool {
|
||||
return c.FT_IS_TRICKY(self.handle);
|
||||
}
|
||||
|
||||
pub fn ascender(self: Face) i16 {
|
||||
return self.handle.*.ascender;
|
||||
}
|
||||
|
||||
pub fn descender(self: Face) i16 {
|
||||
return self.handle.*.descender;
|
||||
}
|
||||
|
||||
pub fn emSize(self: Face) u16 {
|
||||
return self.handle.*.units_per_EM;
|
||||
}
|
||||
|
||||
pub fn height(self: Face) i16 {
|
||||
return self.handle.*.height;
|
||||
}
|
||||
|
||||
pub fn maxAdvanceWidth(self: Face) i16 {
|
||||
return self.handle.*.max_advance_width;
|
||||
}
|
||||
|
||||
pub fn maxAdvanceHeight(self: Face) i16 {
|
||||
return self.handle.*.max_advance_height;
|
||||
}
|
||||
|
||||
pub fn underlinePosition(self: Face) i16 {
|
||||
return self.handle.*.underline_position;
|
||||
}
|
||||
|
||||
pub fn underlineThickness(self: Face) i16 {
|
||||
return self.handle.*.underline_thickness;
|
||||
}
|
||||
|
||||
pub fn numFaces(self: Face) i64 {
|
||||
return self.handle.*.num_faces;
|
||||
}
|
||||
|
||||
pub fn numGlyphs(self: Face) i64 {
|
||||
return self.handle.*.num_glyphs;
|
||||
}
|
||||
|
||||
pub fn familyName(self: Face) ?[:0]const u8 {
|
||||
const family = self.handle.*.family_name;
|
||||
return if (family == null)
|
||||
null
|
||||
else
|
||||
std.mem.span(family);
|
||||
}
|
||||
|
||||
pub fn styleName(self: Face) ?[:0]const u8 {
|
||||
const style = self.handle.*.style_name;
|
||||
return if (style == null)
|
||||
null
|
||||
else
|
||||
std.mem.span(style);
|
||||
}
|
||||
|
||||
pub fn styleFlags(self: Face) StyleFlags {
|
||||
const flags = self.handle.*.style_flags;
|
||||
return utils.bitFieldsToStruct(StyleFlags, StyleFlags.Flag, flags);
|
||||
}
|
||||
|
||||
pub fn sizeMetrics(self: Face) ?SizeMetrics {
|
||||
const size = self.handle.*.size;
|
||||
return if (size == null)
|
||||
null
|
||||
else
|
||||
size.*.metrics;
|
||||
}
|
||||
|
||||
pub fn postscriptName(self: Face) ?[:0]const u8 {
|
||||
const face_name = c.FT_Get_Postscript_Name(self.handle);
|
||||
return if (face_name == null)
|
||||
null
|
||||
else
|
||||
std.mem.span(face_name);
|
||||
}
|
||||
82
freetype/src/Glyph.zig
Normal file
82
freetype/src/Glyph.zig
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
const std = @import("std");
|
||||
const c = @import("c.zig");
|
||||
const BitmapGlyph = @import("BitmapGlyph.zig");
|
||||
const Stroker = @import("Stroker.zig");
|
||||
const types = @import("types.zig");
|
||||
const Error = @import("error.zig").Error;
|
||||
const convertError = @import("error.zig").convertError;
|
||||
|
||||
const Glyph = @This();
|
||||
|
||||
pub const BBox = c.FT_BBox;
|
||||
pub const RenderMode = enum(u3) {
|
||||
normal = c.FT_RENDER_MODE_NORMAL,
|
||||
light = c.FT_RENDER_MODE_LIGHT,
|
||||
mono = c.FT_RENDER_MODE_MONO,
|
||||
lcd = c.FT_RENDER_MODE_LCD,
|
||||
lcd_v = c.FT_RENDER_MODE_LCD_V,
|
||||
sdf = c.FT_RENDER_MODE_SDF,
|
||||
};
|
||||
pub const BBoxMode = enum(u2) {
|
||||
// https://freetype.org/freetype2/docs/reference/ft2-glyph_management.html#ft_glyph_bbox_mode
|
||||
// both `unscaled` and `subpixel` constants are set to 0
|
||||
unscaled_or_subpixels = c.FT_GLYPH_BBOX_UNSCALED,
|
||||
gridfit = c.FT_GLYPH_BBOX_GRIDFIT,
|
||||
truncate = c.FT_GLYPH_BBOX_TRUNCATE,
|
||||
pixels = c.FT_GLYPH_BBOX_PIXELS,
|
||||
};
|
||||
|
||||
handle: c.FT_Glyph,
|
||||
|
||||
pub fn init(handle: c.FT_Glyph) Glyph {
|
||||
return Glyph{ .handle = handle };
|
||||
}
|
||||
|
||||
pub fn deinit(self: Glyph) void {
|
||||
c.FT_Done_Glyph(self.handle);
|
||||
}
|
||||
|
||||
pub fn clone(self: Glyph) Error!Glyph {
|
||||
var res = std.mem.zeroes(c.FT_Glyph);
|
||||
try convertError(c.FT_Glyph_Copy(self.handle, &res));
|
||||
return Glyph.init(res);
|
||||
}
|
||||
|
||||
pub fn transform(self: Glyph, matrix: ?types.Matrix, delta: ?types.Vector) Error!void {
|
||||
var m = matrix orelse std.mem.zeroes(types.Matrix);
|
||||
var d = delta orelse std.mem.zeroes(types.Vector);
|
||||
try convertError(c.FT_Glyph_Transform(self.handle, &m, &d));
|
||||
}
|
||||
|
||||
pub fn getCBox(self: Glyph, bbox_mode: BBoxMode) BBox {
|
||||
var res = std.mem.zeroes(BBox);
|
||||
c.FT_Glyph_Get_CBox(self.handle, @enumToInt(bbox_mode), &res);
|
||||
return res;
|
||||
}
|
||||
|
||||
pub fn toBitmap(self: Glyph, render_mode: RenderMode, origin: ?types.Vector) Error!BitmapGlyph {
|
||||
var res = self.handle;
|
||||
var o = origin orelse std.mem.zeroes(types.Vector);
|
||||
try convertError(c.FT_Glyph_To_Bitmap(&res, @enumToInt(render_mode), &o, 0));
|
||||
return BitmapGlyph.init(@ptrCast(c.FT_BitmapGlyph, self.handle));
|
||||
}
|
||||
|
||||
pub fn stroke(self: Glyph, stroker: Stroker) Error!Glyph {
|
||||
var res = self.handle;
|
||||
try convertError(c.FT_Glyph_Stroke(&res, stroker.handle, 0));
|
||||
return Glyph.init(res);
|
||||
}
|
||||
|
||||
pub fn strokeBorder(self: Glyph, stroker: Stroker, inside: bool) Error!Glyph {
|
||||
var res = self.handle;
|
||||
try convertError(c.FT_Glyph_StrokeBorder(&res, stroker.handle, if (inside) 1 else 0, 0));
|
||||
return Glyph.init(res);
|
||||
}
|
||||
|
||||
pub fn advanceX(self: Glyph) isize {
|
||||
return self.handle.*.advance.x;
|
||||
}
|
||||
|
||||
pub fn advanceY(self: Glyph) isize {
|
||||
return self.handle.*.advance.y;
|
||||
}
|
||||
79
freetype/src/GlyphSlot.zig
Normal file
79
freetype/src/GlyphSlot.zig
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
const std = @import("std");
|
||||
const c = @import("c.zig");
|
||||
const types = @import("types.zig");
|
||||
const Glyph = @import("Glyph.zig");
|
||||
const Outline = @import("Outline.zig");
|
||||
const Bitmap = @import("Bitmap.zig");
|
||||
const Error = @import("error.zig").Error;
|
||||
const convertError = @import("error.zig").convertError;
|
||||
|
||||
const GlyphSlot = @This();
|
||||
|
||||
pub const GlyphMetrics = c.FT_Glyph_Metrics;
|
||||
pub const SubGlyphInfo = struct {
|
||||
index: i32,
|
||||
flags: u32,
|
||||
arg1: i32,
|
||||
arg2: i32,
|
||||
transform: types.Matrix,
|
||||
};
|
||||
|
||||
handle: c.FT_GlyphSlot,
|
||||
|
||||
pub fn init(handle: c.FT_GlyphSlot) GlyphSlot {
|
||||
return GlyphSlot{ .handle = handle };
|
||||
}
|
||||
|
||||
pub fn render(self: GlyphSlot, render_mode: Glyph.RenderMode) Error!void {
|
||||
return convertError(c.FT_Render_Glyph(self.handle, @enumToInt(render_mode)));
|
||||
}
|
||||
|
||||
pub fn subGlyphInfo(self: GlyphSlot, sub_index: u32) Error!SubGlyphInfo {
|
||||
var info = std.mem.zeroes(SubGlyphInfo);
|
||||
try convertError(c.FT_Get_SubGlyph_Info(self.handle, sub_index, &info.index, &info.flags, &info.arg1, &info.arg2, &info.transform));
|
||||
return info;
|
||||
}
|
||||
|
||||
pub fn glyph(self: GlyphSlot) Error!Glyph {
|
||||
var out = std.mem.zeroes(c.FT_Glyph);
|
||||
try convertError(c.FT_Get_Glyph(self.handle, &out));
|
||||
return Glyph.init(out);
|
||||
}
|
||||
|
||||
pub fn outline(self: GlyphSlot) ?Outline {
|
||||
const out = self.handle.*.outline;
|
||||
const format = self.handle.*.format;
|
||||
|
||||
return if (format == c.FT_GLYPH_FORMAT_OUTLINE)
|
||||
Outline.init(out)
|
||||
else
|
||||
null;
|
||||
}
|
||||
|
||||
pub fn bitmap(self: GlyphSlot) Bitmap {
|
||||
return Bitmap.init(self.handle.*.bitmap);
|
||||
}
|
||||
|
||||
pub fn bitmapLeft(self: GlyphSlot) i32 {
|
||||
return self.handle.*.bitmap_left;
|
||||
}
|
||||
|
||||
pub fn bitmapTop(self: GlyphSlot) i32 {
|
||||
return self.handle.*.bitmap_top;
|
||||
}
|
||||
|
||||
pub fn linearHoriAdvance(self: GlyphSlot) i64 {
|
||||
return self.handle.*.linearHoriAdvance;
|
||||
}
|
||||
|
||||
pub fn linearVertAdvance(self: GlyphSlot) i64 {
|
||||
return self.handle.*.linearVertAdvance;
|
||||
}
|
||||
|
||||
pub fn advance(self: GlyphSlot) types.Vector {
|
||||
return self.handle.*.advance;
|
||||
}
|
||||
|
||||
pub fn metrics(self: GlyphSlot) GlyphMetrics {
|
||||
return self.handle.*.metrics;
|
||||
}
|
||||
60
freetype/src/Library.zig
Normal file
60
freetype/src/Library.zig
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
const std = @import("std");
|
||||
const c = @import("c.zig");
|
||||
const types = @import("types.zig");
|
||||
const Face = @import("Face.zig");
|
||||
const Stroker = @import("Stroker.zig");
|
||||
const Error = @import("error.zig").Error;
|
||||
const convertError = @import("error.zig").convertError;
|
||||
|
||||
const Library = @This();
|
||||
|
||||
pub const LcdFilter = enum(u5) {
|
||||
none = c.FT_LCD_FILTER_NONE,
|
||||
default = c.FT_LCD_FILTER_DEFAULT,
|
||||
light = c.FT_LCD_FILTER_LIGHT,
|
||||
legacy = c.FT_LCD_FILTER_LEGACY,
|
||||
};
|
||||
|
||||
handle: c.FT_Library,
|
||||
|
||||
pub fn init() Error!Library {
|
||||
var ft = std.mem.zeroes(Library);
|
||||
try convertError(c.FT_Init_FreeType(&ft.handle));
|
||||
return ft;
|
||||
}
|
||||
|
||||
pub fn deinit(self: Library) void {
|
||||
convertError(c.FT_Done_FreeType(self.handle)) catch |err| {
|
||||
std.log.err("mach/freetype: Failed to deinitialize Library: {}", .{err});
|
||||
};
|
||||
}
|
||||
|
||||
pub fn newFace(self: Library, path: []const u8, face_index: i32) Error!Face {
|
||||
return self.openFace(.{
|
||||
.flags = .{ .path = true },
|
||||
.data = .{ .path = path },
|
||||
}, face_index);
|
||||
}
|
||||
|
||||
pub fn newFaceMemory(self: Library, bytes: []const u8, face_index: i32) Error!Face {
|
||||
return self.openFace(.{
|
||||
.flags = .{ .memory = true },
|
||||
.data = .{ .memory = bytes },
|
||||
}, face_index);
|
||||
}
|
||||
|
||||
pub fn openFace(self: Library, args: types.OpenArgs, face_index: i32) Error!Face {
|
||||
var face = std.mem.zeroes(c.FT_Face);
|
||||
try convertError(c.FT_Open_Face(self.handle, &args.toCInterface(), face_index, &face));
|
||||
return Face.init(face);
|
||||
}
|
||||
|
||||
pub fn newStroker(self: Library) Error!Stroker {
|
||||
var stroker = std.mem.zeroes(c.FT_Stroker);
|
||||
try convertError(c.FT_Stroker_New(self.handle, &stroker));
|
||||
return Stroker.init(stroker);
|
||||
}
|
||||
|
||||
pub fn setLcdFilter(self: Library, lcd_filter: LcdFilter) Error!void {
|
||||
return convertError(c.FT_Library_SetLcdFilter(self.handle, @enumToInt(lcd_filter)));
|
||||
}
|
||||
22
freetype/src/Outline.zig
Normal file
22
freetype/src/Outline.zig
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
const c = @import("c.zig");
|
||||
const types = @import("types.zig");
|
||||
|
||||
const Outline = @This();
|
||||
|
||||
handle: c.FT_Outline,
|
||||
|
||||
pub fn init(handle: c.FT_Outline) Outline {
|
||||
return Outline{ .handle = handle };
|
||||
}
|
||||
|
||||
pub fn points(self: Outline) []const types.Vector {
|
||||
return self.handle.points[0..@intCast(u15, self.handle.n_points)];
|
||||
}
|
||||
|
||||
pub fn tags(self: Outline) []const u8 {
|
||||
return self.handle.tags[0..@intCast(u15, self.handle.n_points)];
|
||||
}
|
||||
|
||||
pub fn contours(self: Outline) []const i16 {
|
||||
return self.handle.contours[0..@intCast(u15, self.handle.n_contours)];
|
||||
}
|
||||
32
freetype/src/Stroker.zig
Normal file
32
freetype/src/Stroker.zig
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
const c = @import("c.zig");
|
||||
const Error = @import("error.zig").Error;
|
||||
const convertError = @import("error.zig").convertError;
|
||||
|
||||
const Stroker = @This();
|
||||
|
||||
pub const StrokerLineCap = enum(u2) {
|
||||
butt = c.FT_STROKER_LINECAP_BUTT,
|
||||
round = c.FT_STROKER_LINECAP_ROUND,
|
||||
square = c.FT_STROKER_LINECAP_SQUARE,
|
||||
};
|
||||
|
||||
pub const StrokerLineJoin = enum(u2) {
|
||||
round = c.FT_STROKER_LINEJOIN_ROUND,
|
||||
bevel = c.FT_STROKER_LINEJOIN_BEVEL,
|
||||
miterVariable = c.FT_STROKER_LINEJOIN_MITER_VARIABLE,
|
||||
miterFixed = c.FT_STROKER_LINEJOIN_MITER_FIXED,
|
||||
};
|
||||
|
||||
handle: c.FT_Stroker,
|
||||
|
||||
pub fn init(handle: c.FT_Stroker) Stroker {
|
||||
return Stroker{ .handle = handle };
|
||||
}
|
||||
|
||||
pub fn set(self: Stroker, radius: i32, line_cap: StrokerLineCap, line_join: StrokerLineJoin, miter_limit: i32) void {
|
||||
c.FT_Stroker_Set(self.handle, radius, @enumToInt(line_cap), @enumToInt(line_join), miter_limit);
|
||||
}
|
||||
|
||||
pub fn deinit(self: Stroker) void {
|
||||
c.FT_Stroker_Done(self.handle);
|
||||
}
|
||||
8
freetype/src/c.zig
Normal file
8
freetype/src/c.zig
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
pub usingnamespace @cImport({
|
||||
@cInclude("freetype/freetype.h");
|
||||
@cInclude("freetype/ftlcdfil.h");
|
||||
@cInclude("freetype/ftmodapi.h");
|
||||
@cInclude("freetype/ftstroke.h");
|
||||
@cInclude("freetype/ftsystem.h");
|
||||
@cInclude("ft2build.h");
|
||||
});
|
||||
196
freetype/src/error.zig
Normal file
196
freetype/src/error.zig
Normal file
|
|
@ -0,0 +1,196 @@
|
|||
const c = @import("c.zig");
|
||||
|
||||
pub const Error = error{
|
||||
CannotOpenResource,
|
||||
UnknownFileFormat,
|
||||
InvalidFileFormat,
|
||||
InvalidVersion,
|
||||
LowerModuleVersion,
|
||||
InvalidArgument,
|
||||
UnimplementedFeature,
|
||||
InvalidTable,
|
||||
InvalidOffset,
|
||||
ArrayTooLarge,
|
||||
MissingModule,
|
||||
MissingProperty,
|
||||
InvalidGlyphIndex,
|
||||
InvalidCharacterCode,
|
||||
InvalidGlyphFormat,
|
||||
CannotRenderGlyph,
|
||||
InvalidOutline,
|
||||
InvalidComposite,
|
||||
TooManyHints,
|
||||
InvalidPixelSize,
|
||||
InvalidHandle,
|
||||
InvalidLibraryHandle,
|
||||
InvalidDriverHandle,
|
||||
InvalidFaceHandle,
|
||||
InvalidSizeHandle,
|
||||
InvalidSlotHandle,
|
||||
InvalidCharMapHandle,
|
||||
InvalidCacheHandle,
|
||||
InvalidStreamHandle,
|
||||
TooManyDrivers,
|
||||
TooManyExtensions,
|
||||
OutOfMemory,
|
||||
UnlistedObject,
|
||||
CannotOpenStream,
|
||||
InvalidStreamSeek,
|
||||
InvalidStreamSkip,
|
||||
InvalidStreamRead,
|
||||
InvalidStreamOperation,
|
||||
InvalidFrameOperation,
|
||||
NestedFrameAccess,
|
||||
InvalidFrameRead,
|
||||
RasterUninitialized,
|
||||
RasterCorrupted,
|
||||
RasterOverflow,
|
||||
RasterNegativeHeight,
|
||||
TooManyCaches,
|
||||
InvalidOpcode,
|
||||
TooFewArguments,
|
||||
StackOverflow,
|
||||
CodeOverflow,
|
||||
BadArgument,
|
||||
DivideByZero,
|
||||
InvalidReference,
|
||||
DebugOpCode,
|
||||
ENDFInExecStream,
|
||||
NestedDEFS,
|
||||
InvalidCodeRange,
|
||||
ExecutionTooLong,
|
||||
TooManyFunctionDefs,
|
||||
TooManyInstructionDefs,
|
||||
TableMissing,
|
||||
HorizHeaderMissing,
|
||||
LocationsMissing,
|
||||
NameTableMissing,
|
||||
CMapTableMissing,
|
||||
HmtxTableMissing,
|
||||
PostTableMissing,
|
||||
InvalidHorizMetrics,
|
||||
InvalidCharMapFormat,
|
||||
InvalidPPem,
|
||||
InvalidVertMetrics,
|
||||
CouldNotFindContext,
|
||||
InvalidPostTableFormat,
|
||||
InvalidPostTable,
|
||||
Syntax,
|
||||
StackUnderflow,
|
||||
Ignore,
|
||||
NoUnicodeGlyphName,
|
||||
MissingStartfontField,
|
||||
MissingFontField,
|
||||
MissingSizeField,
|
||||
MissingFontboundingboxField,
|
||||
MissingCharsField,
|
||||
MissingStartcharField,
|
||||
MissingEncodingField,
|
||||
MissingBbxField,
|
||||
BbxTooBig,
|
||||
CorruptedFontHeader,
|
||||
CorruptedFontGlyphs,
|
||||
};
|
||||
|
||||
pub fn convertError(err: c_int) Error!void {
|
||||
return switch (err) {
|
||||
c.FT_Err_Ok => {},
|
||||
c.FT_Err_Cannot_Open_Resource => Error.CannotOpenResource,
|
||||
c.FT_Err_Unknown_File_Format => Error.UnknownFileFormat,
|
||||
c.FT_Err_Invalid_File_Format => Error.InvalidFileFormat,
|
||||
c.FT_Err_Invalid_Version => Error.InvalidVersion,
|
||||
c.FT_Err_Lower_Module_Version => Error.LowerModuleVersion,
|
||||
c.FT_Err_Invalid_Argument => Error.InvalidArgument,
|
||||
c.FT_Err_Unimplemented_Feature => Error.UnimplementedFeature,
|
||||
c.FT_Err_Invalid_Table => Error.InvalidTable,
|
||||
c.FT_Err_Invalid_Offset => Error.InvalidOffset,
|
||||
c.FT_Err_Array_Too_Large => Error.ArrayTooLarge,
|
||||
c.FT_Err_Missing_Module => Error.MissingModule,
|
||||
c.FT_Err_Missing_Property => Error.MissingProperty,
|
||||
c.FT_Err_Invalid_Glyph_Index => Error.InvalidGlyphIndex,
|
||||
c.FT_Err_Invalid_Character_Code => Error.InvalidCharacterCode,
|
||||
c.FT_Err_Invalid_Glyph_Format => Error.InvalidGlyphFormat,
|
||||
c.FT_Err_Cannot_Render_Glyph => Error.CannotRenderGlyph,
|
||||
c.FT_Err_Invalid_Outline => Error.InvalidOutline,
|
||||
c.FT_Err_Invalid_Composite => Error.InvalidComposite,
|
||||
c.FT_Err_Too_Many_Hints => Error.TooManyHints,
|
||||
c.FT_Err_Invalid_Pixel_Size => Error.InvalidPixelSize,
|
||||
c.FT_Err_Invalid_Handle => Error.InvalidHandle,
|
||||
c.FT_Err_Invalid_Library_Handle => Error.InvalidLibraryHandle,
|
||||
c.FT_Err_Invalid_Driver_Handle => Error.InvalidDriverHandle,
|
||||
c.FT_Err_Invalid_Face_Handle => Error.InvalidFaceHandle,
|
||||
c.FT_Err_Invalid_Size_Handle => Error.InvalidSizeHandle,
|
||||
c.FT_Err_Invalid_Slot_Handle => Error.InvalidSlotHandle,
|
||||
c.FT_Err_Invalid_CharMap_Handle => Error.InvalidCharMapHandle,
|
||||
c.FT_Err_Invalid_Cache_Handle => Error.InvalidCacheHandle,
|
||||
c.FT_Err_Invalid_Stream_Handle => Error.InvalidStreamHandle,
|
||||
c.FT_Err_Too_Many_Drivers => Error.TooManyDrivers,
|
||||
c.FT_Err_Too_Many_Extensions => Error.TooManyExtensions,
|
||||
c.FT_Err_Out_Of_Memory => Error.OutOfMemory,
|
||||
c.FT_Err_Unlisted_Object => Error.UnlistedObject,
|
||||
c.FT_Err_Cannot_Open_Stream => Error.CannotOpenStream,
|
||||
c.FT_Err_Invalid_Stream_Seek => Error.InvalidStreamSeek,
|
||||
c.FT_Err_Invalid_Stream_Skip => Error.InvalidStreamSkip,
|
||||
c.FT_Err_Invalid_Stream_Read => Error.InvalidStreamRead,
|
||||
c.FT_Err_Invalid_Stream_Operation => Error.InvalidStreamOperation,
|
||||
c.FT_Err_Invalid_Frame_Operation => Error.InvalidFrameOperation,
|
||||
c.FT_Err_Nested_Frame_Access => Error.NestedFrameAccess,
|
||||
c.FT_Err_Invalid_Frame_Read => Error.InvalidFrameRead,
|
||||
c.FT_Err_Raster_Uninitialized => Error.RasterUninitialized,
|
||||
c.FT_Err_Raster_Corrupted => Error.RasterCorrupted,
|
||||
c.FT_Err_Raster_Overflow => Error.RasterOverflow,
|
||||
c.FT_Err_Raster_Negative_Height => Error.RasterNegativeHeight,
|
||||
c.FT_Err_Too_Many_Caches => Error.TooManyCaches,
|
||||
c.FT_Err_Invalid_Opcode => Error.InvalidOpcode,
|
||||
c.FT_Err_Too_Few_Arguments => Error.TooFewArguments,
|
||||
c.FT_Err_Stack_Overflow => Error.StackOverflow,
|
||||
c.FT_Err_Code_Overflow => Error.CodeOverflow,
|
||||
c.FT_Err_Bad_Argument => Error.BadArgument,
|
||||
c.FT_Err_Divide_By_Zero => Error.DivideByZero,
|
||||
c.FT_Err_Invalid_Reference => Error.InvalidReference,
|
||||
c.FT_Err_Debug_OpCode => Error.DebugOpCode,
|
||||
c.FT_Err_ENDF_In_Exec_Stream => Error.ENDFInExecStream,
|
||||
c.FT_Err_Nested_DEFS => Error.NestedDEFS,
|
||||
c.FT_Err_Invalid_CodeRange => Error.InvalidCodeRange,
|
||||
c.FT_Err_Execution_Too_Long => Error.ExecutionTooLong,
|
||||
c.FT_Err_Too_Many_Function_Defs => Error.TooManyFunctionDefs,
|
||||
c.FT_Err_Too_Many_Instruction_Defs => Error.TooManyInstructionDefs,
|
||||
c.FT_Err_Table_Missing => Error.TableMissing,
|
||||
c.FT_Err_Horiz_Header_Missing => Error.HorizHeaderMissing,
|
||||
c.FT_Err_Locations_Missing => Error.LocationsMissing,
|
||||
c.FT_Err_Name_Table_Missing => Error.NameTableMissing,
|
||||
c.FT_Err_CMap_Table_Missing => Error.CMapTableMissing,
|
||||
c.FT_Err_Hmtx_Table_Missing => Error.HmtxTableMissing,
|
||||
c.FT_Err_Post_Table_Missing => Error.PostTableMissing,
|
||||
c.FT_Err_Invalid_Horiz_Metrics => Error.InvalidHorizMetrics,
|
||||
c.FT_Err_Invalid_CharMap_Format => Error.InvalidCharMapFormat,
|
||||
c.FT_Err_Invalid_PPem => Error.InvalidPPem,
|
||||
c.FT_Err_Invalid_Vert_Metrics => Error.InvalidVertMetrics,
|
||||
c.FT_Err_Could_Not_Find_Context => Error.CouldNotFindContext,
|
||||
c.FT_Err_Invalid_Post_Table_Format => Error.InvalidPostTableFormat,
|
||||
c.FT_Err_Invalid_Post_Table => Error.InvalidPostTable,
|
||||
c.FT_Err_Syntax_Error => Error.Syntax,
|
||||
c.FT_Err_Stack_Underflow => Error.StackUnderflow,
|
||||
c.FT_Err_Ignore => Error.Ignore,
|
||||
c.FT_Err_No_Unicode_Glyph_Name => Error.NoUnicodeGlyphName,
|
||||
c.FT_Err_Missing_Startfont_Field => Error.MissingStartfontField,
|
||||
c.FT_Err_Missing_Font_Field => Error.MissingFontField,
|
||||
c.FT_Err_Missing_Size_Field => Error.MissingSizeField,
|
||||
c.FT_Err_Missing_Fontboundingbox_Field => Error.MissingFontboundingboxField,
|
||||
c.FT_Err_Missing_Chars_Field => Error.MissingCharsField,
|
||||
c.FT_Err_Missing_Startchar_Field => Error.MissingStartcharField,
|
||||
c.FT_Err_Missing_Encoding_Field => Error.MissingEncodingField,
|
||||
c.FT_Err_Missing_Bbx_Field => Error.MissingBbxField,
|
||||
c.FT_Err_Bbx_Too_Big => Error.BbxTooBig,
|
||||
c.FT_Err_Corrupted_Font_Header => Error.CorruptedFontHeader,
|
||||
c.FT_Err_Corrupted_Font_Glyphs => Error.CorruptedFontGlyphs,
|
||||
else => unreachable,
|
||||
};
|
||||
}
|
||||
|
||||
test "error convertion" {
|
||||
const expectError = @import("std").testing.expectError;
|
||||
|
||||
try convertError(c.FT_Err_Ok);
|
||||
try expectError(Error.OutOfMemory, convertError(c.FT_Err_Out_Of_Memory));
|
||||
}
|
||||
26
freetype/src/main.zig
Normal file
26
freetype/src/main.zig
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
pub const Library = @import("Library.zig");
|
||||
pub const Face = @import("Face.zig");
|
||||
pub const GlyphSlot = @import("GlyphSlot.zig");
|
||||
pub const Glyph = @import("Glyph.zig");
|
||||
pub const BitmapGlyph = @import("BitmapGlyph.zig");
|
||||
pub const Bitmap = @import("Bitmap.zig");
|
||||
pub const Outline = @import("Outline.zig");
|
||||
pub const Stroker = @import("Stroker.zig");
|
||||
pub const Error = @import("error.zig").Error;
|
||||
pub const C = @import("c.zig");
|
||||
pub usingnamespace @import("types.zig");
|
||||
|
||||
test {
|
||||
const refAllDecls = @import("std").testing.refAllDecls;
|
||||
refAllDecls(@import("Library.zig"));
|
||||
refAllDecls(@import("Face.zig"));
|
||||
refAllDecls(@import("GlyphSlot.zig"));
|
||||
refAllDecls(@import("Glyph.zig"));
|
||||
refAllDecls(@import("BitmapGlyph.zig"));
|
||||
refAllDecls(@import("Bitmap.zig"));
|
||||
refAllDecls(@import("Outline.zig"));
|
||||
refAllDecls(@import("Stroker.zig"));
|
||||
refAllDecls(@import("types.zig"));
|
||||
refAllDecls(@import("error.zig"));
|
||||
refAllDecls(@import("utils.zig"));
|
||||
}
|
||||
56
freetype/src/types.zig
Normal file
56
freetype/src/types.zig
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
const std = @import("std");
|
||||
const c = @import("c.zig");
|
||||
const utils = @import("utils.zig");
|
||||
|
||||
pub const Vector = c.FT_Vector;
|
||||
pub const Matrix = c.FT_Matrix;
|
||||
|
||||
pub const OpenFlags = packed struct {
|
||||
memory: bool = false,
|
||||
stream: bool = false,
|
||||
path: bool = false,
|
||||
driver: bool = false,
|
||||
params: bool = false,
|
||||
|
||||
pub const Flag = enum(u5) {
|
||||
memory = c.FT_OPEN_MEMORY,
|
||||
stream = c.FT_OPEN_STREAM,
|
||||
path = c.FT_OPEN_PATHNAME,
|
||||
driver = c.FT_OPEN_DRIVER,
|
||||
params = c.FT_OPEN_PARAMS,
|
||||
};
|
||||
|
||||
pub fn toBitFields(flags: OpenFlags) u5 {
|
||||
return utils.structToBitFields(u5, Flag, flags);
|
||||
}
|
||||
};
|
||||
|
||||
pub const OpenArgs = struct {
|
||||
flags: OpenFlags,
|
||||
data: union(enum) {
|
||||
memory: []const u8,
|
||||
path: []const u8,
|
||||
stream: c.FT_Stream,
|
||||
driver: c.FT_Module,
|
||||
params: []const c.FT_Parameter,
|
||||
},
|
||||
|
||||
pub fn toCInterface(self: OpenArgs) c.FT_Open_Args {
|
||||
var oa = std.mem.zeroes(c.FT_Open_Args);
|
||||
oa.flags = self.flags.toBitFields();
|
||||
switch (self.data) {
|
||||
.memory => |d| {
|
||||
oa.memory_base = d.ptr;
|
||||
oa.memory_size = @truncate(u31, d.len);
|
||||
},
|
||||
.path => |*d| oa.pathname = @intToPtr(*u8, @ptrToInt(d.ptr)),
|
||||
.stream => |d| oa.stream = d,
|
||||
.driver => |d| oa.driver = d,
|
||||
.params => |*d| {
|
||||
oa.params = @intToPtr(*c.FT_Parameter, @ptrToInt(d.ptr));
|
||||
oa.num_params = @intCast(u31, d.len);
|
||||
},
|
||||
}
|
||||
return oa;
|
||||
}
|
||||
};
|
||||
48
freetype/src/utils.zig
Normal file
48
freetype/src/utils.zig
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
const std = @import("std");
|
||||
const meta = std.meta;
|
||||
const mem = std.mem;
|
||||
const testing = std.testing;
|
||||
|
||||
pub fn structToBitFields(comptime IntType: type, comptime EnumDataType: type, flags: anytype) IntType {
|
||||
var value: IntType = 0;
|
||||
inline for (comptime meta.fieldNames(EnumDataType)) |field_name| {
|
||||
if (@field(flags, field_name)) {
|
||||
value |= @enumToInt(@field(EnumDataType, field_name));
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
pub fn bitFieldsToStruct(comptime StructType: type, comptime EnumDataType: type, flags: anytype) StructType {
|
||||
var value = mem.zeroes(StructType);
|
||||
inline for (comptime meta.fieldNames(EnumDataType)) |field_name| {
|
||||
if (flags & (@enumToInt(@field(EnumDataType, field_name))) != 0) {
|
||||
@field(value, field_name) = true;
|
||||
}
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
const TestEnum = enum(u16) {
|
||||
filed_1 = (1 << 1),
|
||||
filed_2 = (1 << 2),
|
||||
filed_3 = (1 << 3),
|
||||
};
|
||||
|
||||
const TestStruct = packed struct {
|
||||
filed_1: bool = false,
|
||||
filed_2: bool = false,
|
||||
filed_3: bool = false,
|
||||
};
|
||||
|
||||
test "struct fields to bit fields" {
|
||||
try testing.expectEqual(@as(u16, (1 << 1) | (1 << 3)), structToBitFields(u16, TestEnum, TestStruct{
|
||||
.filed_1 = true,
|
||||
.filed_3 = true,
|
||||
}));
|
||||
try testing.expectEqual(@as(u16, 0), structToBitFields(u16, TestEnum, TestStruct{}));
|
||||
}
|
||||
|
||||
test "bit fields to struct" {
|
||||
try testing.expectEqual(TestStruct{ .filed_1 = true, .filed_2 = true, .filed_3 = false }, bitFieldsToStruct(TestStruct, TestEnum, (1 << 1) | (1 << 2)));
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue