pkg/freetype: Library and Face

This commit is contained in:
Mitchell Hashimoto
2022-08-28 17:07:27 -07:00
parent 483bb90cf9
commit 7af9091497
9 changed files with 403 additions and 2 deletions

13
pkg/freetype/Face.zig Normal file
View File

@ -0,0 +1,13 @@
const Face = @This();
const std = @import("std");
const c = @import("c.zig");
const errors = @import("errors.zig");
const Error = errors.Error;
const intToError = errors.intToError;
handle: c.FT_Face,
pub fn deinit(self: Face) void {
_ = c.FT_Done_Face(self.handle);
}

85
pkg/freetype/Library.zig Normal file
View File

@ -0,0 +1,85 @@
const Library = @This();
const std = @import("std");
const c = @import("c.zig");
const Face = @import("Face.zig");
const errors = @import("errors.zig");
const Error = errors.Error;
const intToError = errors.intToError;
handle: c.FT_Library,
/// Initialize a new FreeType library object. The set of modules that are
/// registered by this function is determined at build time.
pub fn init() Error!Library {
var res = Library{ .handle = undefined };
try intToError(c.FT_Init_FreeType(&res.handle));
return res;
}
/// Destroy a given FreeType library object and all of its children,
/// including resources, drivers, faces, sizes, etc.
pub fn deinit(self: Library) void {
_ = c.FT_Done_FreeType(self.handle);
}
/// Return the version of the FreeType library being used. This is useful when
/// dynamically linking to the library, since one cannot use the macros
/// FREETYPE_MAJOR, FREETYPE_MINOR, and FREETYPE_PATCH.
pub fn version(self: Library) Version {
var v: Version = undefined;
c.FT_Library_Version(self.handle, &v.major, &v.minor, &v.patch);
return v;
}
/// Call FT_Open_Face to open a font that has been loaded into memory.
pub fn initMemoryFace(self: Library, data: []const u8, index: i32) Error!Face {
var face: Face = undefined;
try intToError(c.FT_New_Memory_Face(
self.handle,
data.ptr,
@intCast(c_long, data.len),
index,
&face.handle,
));
return face;
}
pub const Version = struct {
major: i32,
minor: i32,
patch: i32,
/// Convert the version to a string. The buffer should be able to
/// accomodate the size, recommended to be at least 8 chars wide.
/// The returned slice will be a slice of buf that contains the full
/// version string.
pub fn toString(self: Version, buf: []u8) ![]const u8 {
return try std.fmt.bufPrint(buf, "{d}.{d}.{d}", .{
self.major, self.minor, self.patch,
});
}
};
test "basics" {
const testing = std.testing;
var lib = try init();
defer lib.deinit();
const vsn = lib.version();
try testing.expect(vsn.major > 1);
var buf: [32]u8 = undefined;
_ = try vsn.toString(&buf);
}
test "loading memory font" {
const font_data = @import("test.zig").font_regular;
var lib = try init();
defer lib.deinit();
var face = try lib.initMemoryFace(font_data, 0);
defer face.deinit();
}

294
pkg/freetype/errors.zig Normal file
View File

@ -0,0 +1,294 @@
const c = @import("c.zig");
// Thanks to Mach (https://github.com/hexops/mach) for this work, I didn't
// do this manually. I wrote the other Freetype bindings by hand but this
// one was... too tedius.
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 intToError(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,
};
}
pub fn errorToInt(err: Error) c_int {
return switch (err) {
Error.CannotOpenResource => c.FT_Err_Cannot_Open_Resource,
Error.UnknownFileFormat => c.FT_Err_Unknown_File_Format,
Error.InvalidFileFormat => c.FT_Err_Invalid_File_Format,
Error.InvalidVersion => c.FT_Err_Invalid_Version,
Error.LowerModuleVersion => c.FT_Err_Lower_Module_Version,
Error.InvalidArgument => c.FT_Err_Invalid_Argument,
Error.UnimplementedFeature => c.FT_Err_Unimplemented_Feature,
Error.InvalidTable => c.FT_Err_Invalid_Table,
Error.InvalidOffset => c.FT_Err_Invalid_Offset,
Error.ArrayTooLarge => c.FT_Err_Array_Too_Large,
Error.MissingModule => c.FT_Err_Missing_Module,
Error.MissingProperty => c.FT_Err_Missing_Property,
Error.InvalidGlyphIndex => c.FT_Err_Invalid_Glyph_Index,
Error.InvalidCharacterCode => c.FT_Err_Invalid_Character_Code,
Error.InvalidGlyphFormat => c.FT_Err_Invalid_Glyph_Format,
Error.CannotRenderGlyph => c.FT_Err_Cannot_Render_Glyph,
Error.InvalidOutline => c.FT_Err_Invalid_Outline,
Error.InvalidComposite => c.FT_Err_Invalid_Composite,
Error.TooManyHints => c.FT_Err_Too_Many_Hints,
Error.InvalidPixelSize => c.FT_Err_Invalid_Pixel_Size,
Error.InvalidHandle => c.FT_Err_Invalid_Handle,
Error.InvalidLibraryHandle => c.FT_Err_Invalid_Library_Handle,
Error.InvalidDriverHandle => c.FT_Err_Invalid_Driver_Handle,
Error.InvalidFaceHandle => c.FT_Err_Invalid_Face_Handle,
Error.InvalidSizeHandle => c.FT_Err_Invalid_Size_Handle,
Error.InvalidSlotHandle => c.FT_Err_Invalid_Slot_Handle,
Error.InvalidCharMapHandle => c.FT_Err_Invalid_CharMap_Handle,
Error.InvalidCacheHandle => c.FT_Err_Invalid_Cache_Handle,
Error.InvalidStreamHandle => c.FT_Err_Invalid_Stream_Handle,
Error.TooManyDrivers => c.FT_Err_Too_Many_Drivers,
Error.TooManyExtensions => c.FT_Err_Too_Many_Extensions,
Error.OutOfMemory => c.FT_Err_Out_Of_Memory,
Error.UnlistedObject => c.FT_Err_Unlisted_Object,
Error.CannotOpenStream => c.FT_Err_Cannot_Open_Stream,
Error.InvalidStreamSeek => c.FT_Err_Invalid_Stream_Seek,
Error.InvalidStreamSkip => c.FT_Err_Invalid_Stream_Skip,
Error.InvalidStreamRead => c.FT_Err_Invalid_Stream_Read,
Error.InvalidStreamOperation => c.FT_Err_Invalid_Stream_Operation,
Error.InvalidFrameOperation => c.FT_Err_Invalid_Frame_Operation,
Error.NestedFrameAccess => c.FT_Err_Nested_Frame_Access,
Error.InvalidFrameRead => c.FT_Err_Invalid_Frame_Read,
Error.RasterUninitialized => c.FT_Err_Raster_Uninitialized,
Error.RasterCorrupted => c.FT_Err_Raster_Corrupted,
Error.RasterOverflow => c.FT_Err_Raster_Overflow,
Error.RasterNegativeHeight => c.FT_Err_Raster_Negative_Height,
Error.TooManyCaches => c.FT_Err_Too_Many_Caches,
Error.InvalidOpcode => c.FT_Err_Invalid_Opcode,
Error.TooFewArguments => c.FT_Err_Too_Few_Arguments,
Error.StackOverflow => c.FT_Err_Stack_Overflow,
Error.CodeOverflow => c.FT_Err_Code_Overflow,
Error.BadArgument => c.FT_Err_Bad_Argument,
Error.DivideByZero => c.FT_Err_Divide_By_Zero,
Error.InvalidReference => c.FT_Err_Invalid_Reference,
Error.DebugOpCode => c.FT_Err_Debug_OpCode,
Error.ENDFInExecStream => c.FT_Err_ENDF_In_Exec_Stream,
Error.NestedDEFS => c.FT_Err_Nested_DEFS,
Error.InvalidCodeRange => c.FT_Err_Invalid_CodeRange,
Error.ExecutionTooLong => c.FT_Err_Execution_Too_Long,
Error.TooManyFunctionDefs => c.FT_Err_Too_Many_Function_Defs,
Error.TooManyInstructionDefs => c.FT_Err_Too_Many_Instruction_Defs,
Error.TableMissing => c.FT_Err_Table_Missing,
Error.HorizHeaderMissing => c.FT_Err_Horiz_Header_Missing,
Error.LocationsMissing => c.FT_Err_Locations_Missing,
Error.NameTableMissing => c.FT_Err_Name_Table_Missing,
Error.CMapTableMissing => c.FT_Err_CMap_Table_Missing,
Error.HmtxTableMissing => c.FT_Err_Hmtx_Table_Missing,
Error.PostTableMissing => c.FT_Err_Post_Table_Missing,
Error.InvalidHorizMetrics => c.FT_Err_Invalid_Horiz_Metrics,
Error.InvalidCharMapFormat => c.FT_Err_Invalid_CharMap_Format,
Error.InvalidPPem => c.FT_Err_Invalid_PPem,
Error.InvalidVertMetrics => c.FT_Err_Invalid_Vert_Metrics,
Error.CouldNotFindContext => c.FT_Err_Could_Not_Find_Context,
Error.InvalidPostTableFormat => c.FT_Err_Invalid_Post_Table_Format,
Error.InvalidPostTable => c.FT_Err_Invalid_Post_Table,
Error.Syntax => c.FT_Err_Syntax_Error,
Error.StackUnderflow => c.FT_Err_Stack_Underflow,
Error.Ignore => c.FT_Err_Ignore,
Error.NoUnicodeGlyphName => c.FT_Err_No_Unicode_Glyph_Name,
Error.MissingStartfontField => c.FT_Err_Missing_Startfont_Field,
Error.MissingFontField => c.FT_Err_Missing_Font_Field,
Error.MissingSizeField => c.FT_Err_Missing_Size_Field,
Error.MissingFontboundingboxField => c.FT_Err_Missing_Fontboundingbox_Field,
Error.MissingCharsField => c.FT_Err_Missing_Chars_Field,
Error.MissingStartcharField => c.FT_Err_Missing_Startchar_Field,
Error.MissingEncodingField => c.FT_Err_Missing_Encoding_Field,
Error.MissingBbxField => c.FT_Err_Missing_Bbx_Field,
Error.BbxTooBig => c.FT_Err_Bbx_Too_Big,
Error.CorruptedFontHeader => c.FT_Err_Corrupted_Font_Header,
Error.CorruptedFontGlyphs => c.FT_Err_Corrupted_Font_Glyphs,
};
}
test "error convertion" {
const expectError = @import("std").testing.expectError;
try intToError(c.FT_Err_Ok);
try expectError(Error.OutOfMemory, intToError(c.FT_Err_Out_Of_Memory));
}

View File

@ -1 +1,9 @@
pub const c = @import("c.zig");
pub const testing = @import("test.zig");
pub const Face = @import("Face.zig");
pub const Library = @import("Library.zig");
pub usingnamespace @import("errors.zig");
test {
@import("std").testing.refAllDecls(@This());
}

1
pkg/freetype/test.zig Normal file
View File

@ -0,0 +1 @@
pub const font_regular = @embedFile("res/FiraCode-Regular.ttf");

View File

@ -48,7 +48,7 @@ pub fn setFontFuncs(font: Font) void {
test {
const testing = std.testing;
const testFont = @import("test.zig").fontRegular;
const testFont = freetype.testing.font_regular;
const ftc = freetype.c;
const ftok = ftc.FT_Err_Ok;

View File

@ -1 +0,0 @@
pub const fontRegular = @embedFile("res/FiraCode.ttf");

View File

@ -2,6 +2,7 @@ const builtin = @import("builtin");
const options = @import("build_options");
const std = @import("std");
const glfw = @import("glfw");
const freetype = @import("freetype");
const harfbuzz = @import("harfbuzz");
const tracy = @import("tracy");