freetype: ~99% Core-API Coverage

- breaking structure changes
- optimazed examples
- more tests
This commit is contained in:
Ali Chraghi 2022-06-07 00:12:29 +04:30 committed by Stephen Gutekanst
parent db377459c4
commit 04a0a79ef6
21 changed files with 1176 additions and 549 deletions

View file

@ -40,6 +40,10 @@ pub fn build(b: *std.build.Builder) !void {
const example_run_cmd = example_exe.run();
example_run_cmd.step.dependOn(b.getInstallStep());
if (b.args) |args| {
example_run_cmd.addArgs(args);
}
const example_run_step = b.step("run-example-" ++ example, "Run '" ++ example ++ "' example");
example_run_step.dependOn(&example_run_cmd.step);
}

View file

@ -33,7 +33,7 @@ const OutlinePrinter = struct {
}
pub fn outlineExists(self: Self) bool {
const outline = self.face.glyph.outline() orelse return false;
const outline = self.face.glyph().outline() orelse return false;
if (outline.numContours() <= 0 or outline.numPoints() <= 0)
return false;
outline.check() catch return false;
@ -48,7 +48,7 @@ const OutlinePrinter = struct {
.yx = 0 * multiplier,
.yy = -1 * multiplier,
};
self.face.glyph.outline().?.transform(matrix);
self.face.glyph().outline().?.transform(matrix);
}
pub fn extractOutline(self: *Self) !void {
@ -61,12 +61,12 @@ const OutlinePrinter = struct {
.shift = 0,
.delta = 0,
};
try self.face.glyph.outline().?.decompose(self, callbacks);
try self.face.glyph().outline().?.decompose(self, callbacks);
try self.path_stream.writer().writeAll("' fill='#000'/>");
}
pub fn computeViewBox(self: *Self) !void {
const boundingBox = try self.face.glyph.outline().?.bbox();
const boundingBox = try self.face.glyph().outline().?.bbox();
self.xMin = boundingBox.xMin;
self.yMin = boundingBox.yMin;
self.width = boundingBox.xMax - boundingBox.xMin;
@ -99,7 +99,7 @@ const OutlinePrinter = struct {
self.path_stream.writer().print("C {d} {d}, {d} {d}, {d} {d}\t", .{ control_0.x, control_0.y, control_1.x, control_1.y, to.x, to.y }) catch unreachable;
}
pub fn run(self: *Self, symbol: u8) !void {
pub fn run(self: *Self, symbol: u32) !void {
try self.face.loadChar(symbol, .{ .no_scale = true, .no_bitmap = true });
if (!self.outlineExists())
@ -118,5 +118,5 @@ pub fn main() !void {
var outline_printer = try OutlinePrinter.init(file);
defer outline_printer.deinit();
try outline_printer.run('a');
try outline_printer.run(@as(u32, 'ë'));
}

View file

@ -1,52 +1,27 @@
// zig build run-example-single-glyph -- B
const std = @import("std");
const freetype = @import("freetype");
const WIDTH = 32;
const HEIGHT = 24;
fn drawBitmap(bitmap: freetype.Bitmap, x: usize, y: usize) [HEIGHT][WIDTH]u8 {
var figure = std.mem.zeroes([HEIGHT][WIDTH]u8);
var p: usize = 0;
var q: usize = 0;
const w = bitmap.width();
const x_max = x + w;
const y_max = y + bitmap.rows();
var i: usize = 0;
while (i < x_max - x) : (i += 1) {
var j: usize = 0;
while (j < y_max - y) : (j += 1) {
if (i < WIDTH and j < HEIGHT) {
figure[j][i] |= bitmap.buffer()[q * w + p];
q += 1;
}
}
q = 0;
p += 1;
}
return figure;
}
pub fn main() !void {
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
defer _ = gpa.deinit();
const allocator = gpa.allocator();
var args = try std.process.argsAlloc(allocator);
defer std.process.argsFree(allocator, args);
const lib = try freetype.Library.init();
defer lib.deinit();
const face = try lib.newFace("upstream/assets/FiraSans-Regular.ttf", 0);
defer face.deinit();
try face.setCharSize(40 * 64, 0, 50, 0);
try face.loadChar('@', .{ .render = true });
const glyph = face.glyph;
const x = @intCast(usize, glyph.bitmapLeft());
const y = HEIGHT - @intCast(usize, glyph.bitmapTop());
var figure = drawBitmap(glyph.bitmap(), x, y);
try face.setCharSize(60 * 48, 0, 50, 0);
try face.loadChar(args[1][0], .{ .render = true });
const bitmap = face.glyph().bitmap();
var i: usize = 0;
while (i < HEIGHT) : (i += 1) {
while (i < bitmap.rows()) : (i += 1) {
var j: usize = 0;
while (j < WIDTH) : (j += 1) {
const char: u8 = switch (figure[i][j]) {
while (j < bitmap.width()) : (j += 1) {
const char: u8 = switch (bitmap.buffer()[i * bitmap.width() + j]) {
0 => ' ',
1...128 => ';',
else => '#',

View file

@ -1,54 +0,0 @@
const std = @import("std");
const c = @import("c.zig");
const Error = @import("error.zig").Error;
const intToError = @import("error.zig").intToError;
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];
}

View file

@ -1,35 +0,0 @@
const std = @import("std");
const c = @import("c.zig");
const Bitmap = @import("Bitmap.zig");
const Error = @import("error.zig").Error;
const intToError = @import("error.zig").intToError;
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 intToError(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);
}

View file

@ -1,101 +1,59 @@
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 intToError = @import("error.zig").intToError;
const utils = @import("utils.zig");
const intToError = @import("error.zig").intToError;
const Error = @import("error.zig").Error;
const GlyphSlot = @import("freetype.zig").GlyphSlot;
const LoadFlags = @import("freetype.zig").LoadFlags;
const FaceFlags = @import("freetype.zig").FaceFlags;
const StyleFlags = @import("freetype.zig").StyleFlags;
const FSType = @import("freetype.zig").FSType;
const OpenArgs = @import("freetype.zig").OpenArgs;
const KerningMode = @import("freetype.zig").KerningMode;
const Encoding = @import("freetype.zig").Encoding;
const CharMap = @import("freetype.zig").CharMap;
const Size = @import("freetype.zig").Size;
const SizeRequest = @import("freetype.zig").SizeRequest;
const BitmapSize = @import("freetype.zig").BitmapSize;
const Matrix = @import("types.zig").Matrix;
const BBox = @import("types.zig").BBox;
const Vector = @import("image.zig").Vector;
const RootTransform = @import("color.zig").RootTransform;
const PaintFormat = @import("color.zig").PaintFormat;
const Color = @import("color.zig").Color;
const ClipBox = @import("color.zig").ClipBox;
const OpaquePaint = @import("color.zig").OpaquePaint;
const Paint = @import("color.zig").Paint;
const PaletteData = @import("color.zig").PaletteData;
const GlyphLayersIterator = @import("color.zig").GlyphLayersIterator;
const Face = @This();
pub const SizeMetrics = extern struct {
x_ppem: u16,
y_ppem: u16,
x_scale: c_long,
y_scale: c_long,
ascender: c_long,
descender: c_long,
height: c_long,
max_advance: c_long,
};
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 CharmapIterator = struct {
face: Face,
index: u32,
charcode: u32,
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 fn init(face: Face) CharmapIterator {
var i: u32 = 0;
const cc = c.FT_Get_First_Char(face.handle, &i);
return .{
.face = face,
.index = i,
.charcode = @intCast(u32, cc),
};
}
};
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);
pub fn next(self: *CharmapIterator) ?u32 {
self.charcode = @intCast(u32, c.FT_Get_Next_Char(self.face.handle, self.charcode, &self.index));
return if (self.index != 0)
self.charcode
else
null;
}
};
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 {
intToError(c.FT_Done_Face(self.handle)) catch |err| {
@ -117,8 +75,16 @@ pub fn attachMemory(self: Face, bytes: []const u8) Error!void {
});
}
pub fn attachStream(self: Face, args: types.OpenArgs) Error!void {
return intToError(c.FT_Attach_Stream(self.handle, &args.toCInterface()));
pub fn attachStream(self: Face, args: OpenArgs) Error!void {
return intToError(c.FT_Attach_Stream(self.handle, &args.cast()));
}
pub fn loadGlyph(self: Face, index: u32, flags: LoadFlags) Error!void {
return intToError(c.FT_Load_Glyph(self.handle, index, flags.cast()));
}
pub fn loadChar(self: Face, char: u32, flags: LoadFlags) Error!void {
return intToError(c.FT_Load_Char(self.handle, char, flags.cast()));
}
pub fn setCharSize(self: Face, pt_width: i32, pt_height: i32, horz_resolution: u16, vert_resolution: u16) Error!void {
@ -129,29 +95,277 @@ pub fn setPixelSizes(self: Face, pixel_width: u32, pixel_height: u32) Error!void
return intToError(c.FT_Set_Pixel_Sizes(self.handle, pixel_width, pixel_height));
}
pub fn loadGlyph(self: Face, index: u32, flags: LoadFlags) Error!void {
return intToError(c.FT_Load_Glyph(self.handle, index, flags.toBitFields()));
pub fn requestSize(self: Face, req: SizeRequest) Error!void {
var req_mut = req;
return intToError(c.FT_Request_Size(self.handle, &req_mut));
}
pub fn loadChar(self: Face, char: u32, flags: LoadFlags) Error!void {
return intToError(c.FT_Load_Char(self.handle, char, flags.toBitFields()));
pub fn selectSize(self: Face, strike_index: i32) Error!void {
return intToError(c.FT_Select_Size(self.handle, strike_index));
}
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, @ptrCast(*c.FT_Matrix, &m), @ptrCast(*c.FT_Vector, &d));
pub fn setTransform(self: Face, matrix: ?Matrix, delta: ?Vector) Error!void {
var matrix_mut = matrix;
var delta_mut = delta;
return c.FT_Set_Transform(self.handle, if (matrix_mut) |*m| m else null, if (delta_mut) |*d| d else null);
}
pub fn getCharIndex(self: Face, index: u32) ?u32 {
const i = c.FT_Get_Char_Index(self.handle, index);
pub fn getTransform(self: Face) std.meta.Tuple(&.{ Matrix, Vector }) {
var matrix: Matrix = undefined;
var delta: Vector = undefined;
c.FT_Get_Transform(self.handle, &matrix, &delta);
return .{ matrix, delta };
}
pub fn getCharIndex(self: Face, char: u32) ?u32 {
const i = c.FT_Get_Char_Index(self.handle, char);
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 intToError(c.FT_Get_Kerning(self.handle, left_char_index, right_char_index, @enumToInt(mode), @ptrCast(*c.FT_Vector, &vec)));
return vec;
pub fn getNameIndex(self: Face, name: [:0]const u8) ?u32 {
const i = c.FT_Get_Name_Index(self.handle, name);
return if (i == 0) null else i;
}
pub fn getKerning(self: Face, left_char_index: u32, right_char_index: u32, mode: KerningMode) Error!Vector {
var kerning: Vector = undefined;
try intToError(c.FT_Get_Kerning(self.handle, left_char_index, right_char_index, @enumToInt(mode), &kerning));
return kerning;
}
pub fn getTrackKerning(self: Face, point_size: i32, degree: i32) Error!i32 {
var kerning: i32 = 0;
try intToError(c.FT_Get_Track_Kerning(self.handle, point_size, degree, &@intCast(c_long, kerning)));
return kerning;
}
pub fn getGlyphName(self: Face, index: u32) Error![]const u8 {
var name_buf: [30]u8 = undefined;
try intToError(c.FT_Get_Glyph_Name(self.handle, index, &name_buf, 30));
return std.mem.sliceTo(&name_buf, 0);
}
pub fn getPostscriptName(self: Face) ?[:0]const u8 {
return if (c.FT_Get_Postscript_Name(self.handle)) |face_name|
std.mem.span(face_name)
else
null;
}
pub fn getCharmapIterator(self: Face) CharmapIterator {
return CharmapIterator.init(self);
}
pub fn selectCharmap(self: Face, encoding: Encoding) Error!void {
return intToError(c.FT_Select_Charmap(self.handle, @enumToInt(encoding)));
}
pub fn setCharmap(self: Face, char_map: *CharMap) Error!void {
return intToError(c.FT_Set_Charmap(self.handle, char_map));
}
pub fn getFSTypeFlags(self: Face) FSType {
return FSType.from(@intCast(u10, c.FT_Get_FSType_Flags(self.handle)));
}
pub fn getCharVariantIndex(self: Face, char: u32, variant_selector: u32) ?u32 {
return switch (c.FT_Face_GetCharVariantIndex(self.handle, char, variant_selector)) {
0 => null,
else => |i| i,
};
}
pub fn getCharVariantIsDefault(self: Face, char: u32, variant_selector: u32) ?bool {
return switch (c.FT_Face_GetCharVariantIsDefault(self.handle, char, variant_selector)) {
-1 => null,
0 => false,
1 => true,
else => unreachable,
};
}
pub fn getVariantSelectors(self: Face) ?[]u32 {
return if (c.FT_Face_GetVariantSelectors(self.handle)) |chars|
@ptrCast([]u32, std.mem.sliceTo(chars, 0))
else
null;
}
pub fn getVariantsOfChar(self: Face, char: u32) ?[]u32 {
return if (c.FT_Face_GetVariantsOfChar(self.handle, char)) |variants|
@ptrCast([]u32, std.mem.sliceTo(variants, 0))
else
null;
}
pub fn getCharsOfVariant(self: Face, variant_selector: u32) ?[]u32 {
return if (c.FT_Face_GetCharsOfVariant(self.handle, variant_selector)) |chars|
@ptrCast([]u32, std.mem.sliceTo(chars, 0))
else
null;
}
pub fn getPaletteData(self: Face) Error!PaletteData {
var p: c.FT_Palette_Data = undefined;
try intToError(c.FT_Palette_Data_Get(self.handle, &p));
return PaletteData{ .handle = p };
}
fn selectPalette(self: Face, index: u16) Error!?[]const Color {
var color: [*:0]Color = undefined;
try intToError(c.FT_Palette_Select(self.handle, index, &color));
const pd = try getPaletteData();
return self.color[0..pd.numPaletteEntries()];
}
pub fn setPaletteForegroundColor(self: Face, color: Color) Error!void {
try intToError(c.FT_Palette_Set_Foreground_Color(self.handle, color));
}
pub fn getGlyphLayersIterator(self: Face, glyph_index: u32) GlyphLayersIterator {
return GlyphLayersIterator.init(self, glyph_index);
}
pub fn getColorGlyphPaint(self: Face, base_glyph: u32, root_transform: RootTransform) ?Paint {
var opaque_paint: OpaquePaint = undefined;
if (c.FT_Get_Color_Glyph_Paint(self.handle, base_glyph, @enumToInt(root_transform), &opaque_paint) == 0)
return null;
return self.getPaint(opaque_paint);
}
pub fn getColorGlyphClibBox(self: Face, base_glyph: u32) ?ClipBox {
var clib_box: ClipBox = undefined;
if (c.FT_Get_Color_Glyph_ClipBox(self.handle, base_glyph, &clib_box) == 0)
return null;
return clib_box;
}
pub fn getPaint(self: Face, opaque_paint: OpaquePaint) ?Paint {
var p: c.FT_COLR_Paint = undefined;
if (c.FT_Get_Paint(self.handle, opaque_paint, &p) == 0)
return null;
return switch (@intToEnum(PaintFormat, p.format)) {
.color_layers => Paint{ .color_layers = p.u.colr_layers },
.glyph => Paint{ .glyph = p.u.glyph },
.solid => Paint{ .solid = p.u.solid },
.linear_gradient => Paint{ .linear_gradient = p.u.linear_gradient },
.radial_gradient => Paint{ .radial_gradient = p.u.radial_gradient },
.sweep_gradient => Paint{ .sweep_gradient = p.u.sweep_gradient },
.transform => Paint{ .transform = p.u.transform },
.translate => Paint{ .translate = p.u.translate },
.scale => Paint{ .scale = p.u.scale },
.rotate => Paint{ .rotate = p.u.rotate },
.skew => Paint{ .skew = p.u.skew },
.composite => Paint{ .composite = p.u.composite },
.color_glyph => Paint{ .color_glyph = p.u.colr_glyph },
};
}
pub fn newSize(self: Face) Error!Size {
var s: c.FT_Size = undefined;
try intToError(c.FT_New_Size(self.handle, &s));
return Size{ .handle = s };
}
pub fn numFaces(self: Face) u32 {
return @intCast(u32, self.handle.*.num_faces);
}
pub fn faceIndex(self: Face) u32 {
return @intCast(u32, self.handle.*.face_index);
}
pub fn faceFlags(self: Face) FaceFlags {
return FaceFlags.from(@intCast(u19, self.handle.*.face_flags));
}
pub fn styleFlags(self: Face) StyleFlags {
return StyleFlags.from(@intCast(u2, self.handle.*.style_flags));
}
pub fn numGlyphs(self: Face) u32 {
return @intCast(u32, self.handle.*.num_glyphs);
}
pub fn familyName(self: Face) ?[:0]const u8 {
return if (self.handle.*.family_name) |family|
std.mem.span(family)
else
null;
}
pub fn styleName(self: Face) ?[:0]const u8 {
return if (self.handle.*.style_name) |style_name|
std.mem.span(style_name)
else
null;
}
pub fn numFixedSizes(self: Face) u32 {
return @intCast(u32, self.handle.*.num_fixed_sizes);
}
pub fn availableSizes(self: Face) ?BitmapSize {
return if (self.handle.*.available_sizes != null)
self.handle.*.available_sizes.*
else
null;
}
pub fn numCharmaps(self: Face) u32 {
return @intCast(u32, self.handle.*.num_charmaps);
}
pub fn charmaps(self: Face) []const CharMap {
return @ptrCast([]const CharMap, self.handle.*.charmaps[0..self.numCharmaps()]);
}
pub fn bbox(self: Face) BBox {
return self.handle.*.bbox;
}
pub fn unitsPerEM(self: Face) u16 {
return self.handle.*.units_per_EM;
}
pub fn ascender(self: Face) i16 {
return self.handle.*.ascender;
}
pub fn descender(self: Face) i16 {
return self.handle.*.descender;
}
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 glyph(self: Face) GlyphSlot {
return .{ .handle = self.handle.*.glyph };
}
pub fn size(self: Face) Size {
return Size{ .handle = self.handle.*.size };
}
pub fn charmap(self: Face) CharMap {
return self.handle.*.charmap.*;
}
pub fn hasHorizontal(self: Face) bool {
@ -197,76 +411,3 @@ pub fn isCidKeyed(self: Face) bool {
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 {
return if (self.handle.*.family_name) |family|
std.mem.span(family)
else
null;
}
pub fn styleName(self: Face) ?[:0]const u8 {
return if (self.handle.*.style_name) |style_name|
std.mem.span(style_name)
else
null;
}
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 {
return if (self.handle.*.size) |size|
@ptrCast(*SizeMetrics, &size.*.metrics).*
else
null;
}
pub fn postscriptName(self: Face) ?[:0]const u8 {
return if (c.FT_Get_Postscript_Name(self.handle)) |face_name|
std.mem.span(face_name)
else
null;
}

View file

@ -1,76 +1,86 @@
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 intToError = @import("error.zig").intToError;
const Error = @import("error.zig").Error;
const Stroker = @import("Stroker.zig");
const Library = @import("freetype.zig").Library;
const RenderMode = @import("freetype.zig").RenderMode;
const SizeMetrics = @import("freetype.zig").SizeMetrics;
const Matrix = @import("types.zig").Matrix;
const BBox = @import("types.zig").BBox;
const Outline = @import("image.zig").Outline;
const GlyphFormat = @import("image.zig").GlyphFormat;
const Vector = @import("image.zig").Vector;
const Bitmap = @import("image.zig").Bitmap;
const Glyph = @This();
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
// both `unscaled` and `subpixel` 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,
};
pub const GlyphMetrics = c.FT_Glyph_Metrics;
pub const GlyphFormat = enum(u32) {
none = c.FT_GLYPH_FORMAT_NONE,
composite = c.FT_GLYPH_FORMAT_COMPOSITE,
bitmap = c.FT_GLYPH_FORMAT_BITMAP,
outline = c.FT_GLYPH_FORMAT_OUTLINE,
plotter = c.FT_GLYPH_FORMAT_PLOTTER,
svg = c.FT_GLYPH_FORMAT_SVG,
};
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 intToError(c.FT_Glyph_Copy(self.handle, &res));
return Glyph.init(res);
pub fn newGlyph(library: Library, glyph_format: GlyphFormat) Glyph {
var g: c.FT_Glyph = undefined;
return .{
.handle = c.FT_New_Glyph(library.handle, @enumToInt(glyph_format), &g),
};
}
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 intToError(c.FT_Glyph_Transform(self.handle, @ptrCast(*c.FT_Matrix, &m), @ptrCast(*c.FT_Vector, &d)));
pub fn copy(self: Glyph) Error!Glyph {
var g: c.FT_Glyph = undefined;
try intToError(c.FT_Glyph_Copy(self.handle, &g));
return Glyph{ .handle = g };
}
pub fn getCBox(self: Glyph, bbox_mode: BBoxMode) types.BBox {
var res = std.mem.zeroes(types.BBox);
c.FT_Glyph_Get_CBox(self.handle, @enumToInt(bbox_mode), @ptrCast(*c.FT_BBox, &res));
return res;
pub fn transform(self: Glyph, matrix: ?Matrix, delta: ?Vector) Error!void {
try intToError(c.FT_Glyph_Transform(self.handle, if (matrix) |m| &m else null, if (delta) |d| &d else null));
}
pub fn toBitmap(self: Glyph, render_mode: types.RenderMode, origin: ?types.Vector) Error!BitmapGlyph {
var res = self.handle;
var o = origin orelse std.mem.zeroes(types.Vector);
try intToError(c.FT_Glyph_To_Bitmap(&res, @enumToInt(render_mode), @ptrCast(*c.FT_Vector, &o), 0));
return BitmapGlyph.init(@ptrCast(c.FT_BitmapGlyph, self.handle));
pub fn getCBox(self: Glyph, bbox_mode: BBoxMode) BBox {
var b: BBox = undefined;
c.FT_Glyph_Get_CBox(self.handle, @enumToInt(bbox_mode), &b);
return b;
}
pub fn stroke(self: Glyph, stroker: Stroker) Error!Glyph {
var res = self.handle;
try intToError(c.FT_Glyph_Stroke(&res, stroker.handle, 0));
return Glyph.init(res);
pub fn toBitmapGlyph(self: *Glyph, render_mode: RenderMode, origin: ?Vector) Error!BitmapGlyph {
try intToError(c.FT_Glyph_To_Bitmap(&self.handle, @enumToInt(render_mode), if (origin) |o| &o else null, 1));
return BitmapGlyph{ .handle = @ptrCast(c.FT_BitmapGlyph, self.handle) };
}
pub fn strokeBorder(self: Glyph, stroker: Stroker, inside: bool) Error!Glyph {
var res = self.handle;
try intToError(c.FT_Glyph_StrokeBorder(&res, stroker.handle, if (inside) 1 else 0, 0));
return Glyph.init(res);
pub fn copyBitmapGlyph(self: *Glyph, render_mode: RenderMode, origin: ?Vector) Error!BitmapGlyph {
try intToError(c.FT_Glyph_To_Bitmap(&self.handle, @enumToInt(render_mode), if (origin) |o| &o else null, 0));
return BitmapGlyph{ .handle = @ptrCast(c.FT_BitmapGlyph, self.handle) };
}
pub fn castBitmapGlyph(self: Glyph) Error!BitmapGlyph {
return BitmapGlyph{ .handle = @ptrCast(c.FT_BitmapGlyph, self.handle) };
}
pub fn castOutlineGlyph(self: Glyph) Error!OutlineGlyph {
return OutlineGlyph{ .handle = @ptrCast(c.FT_OutlineGlyph, self.handle) };
}
pub fn castSvgGlyph(self: Glyph) Error!SvgGlyph {
return SvgGlyph{ .handle = @ptrCast(c.FT_SvgGlyph, self.handle) };
}
pub fn stroke(self: *Glyph, stroker: Stroker) Error!void {
try intToError(c.FT_Glyph_Stroke(&self.handle, stroker.handle, 0));
}
pub fn strokeBorder(self: *Glyph, stroker: Stroker, inside: bool) Error!void {
try intToError(c.FT_Glyph_StrokeBorder(&self.handle, stroker.handle, if (inside) 1 else 0, 0));
}
pub fn format(self: Glyph) GlyphFormat {
@ -84,3 +94,79 @@ pub fn advanceX(self: Glyph) isize {
pub fn advanceY(self: Glyph) isize {
return self.handle.*.advance.y;
}
const SvgGlyph = struct {
handle: c.FT_SvgGlyph,
pub fn deinit(self: SvgGlyph) void {
c.FT_Done_Glyph(@ptrCast(c.FT_Glyph, self.handle));
}
pub fn svgBuffer(self: SvgGlyph) []const u8 {
return self.handle.*.svg_document[0..self.svgBufferLen()];
}
pub fn svgBufferLen(self: SvgGlyph) usize {
return self.handle.*.svg_document_length;
}
pub fn glyphIndex(self: SvgGlyph) usize {
return self.handle.*.glyph_index;
}
pub fn metrics(self: SvgGlyph) SizeMetrics {
return self.handle.*.metrics;
}
pub fn unitsPerEM(self: SvgGlyph) u16 {
return self.handle.*.units_per_EM;
}
pub fn startGlyphID(self: SvgGlyph) u16 {
return self.handle.*.start_glyph_id;
}
pub fn endGlyphID(self: SvgGlyph) u16 {
return self.handle.*.end_glyph_id;
}
pub fn transform(self: SvgGlyph) Matrix {
return self.handle.*.transform;
}
pub fn delta(self: SvgGlyph) Vector {
return self.handle.*.delta;
}
};
pub const BitmapGlyph = struct {
handle: c.FT_BitmapGlyph,
pub fn deinit(self: BitmapGlyph) void {
c.FT_Done_Glyph(@ptrCast(c.FT_Glyph, self.handle));
}
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 .{ .handle = self.handle.*.bitmap };
}
};
pub const OutlineGlyph = struct {
handle: c.FT_OutlineGlyph,
pub fn deinit(self: OutlineGlyph) void {
c.FT_Done_Glyph(@ptrCast(c.FT_Glyph, self.handle));
}
pub fn outline(self: OutlineGlyph) Outline {
return .{ .handle = &self.handle.*.outline };
}
};

View file

@ -1,11 +1,16 @@
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 intToError = @import("error.zig").intToError;
const Error = @import("error.zig").Error;
const Glyph = @import("Glyph.zig");
const Library = @import("freetype.zig").Library;
const Face = @import("freetype.zig").Face;
const RenderMode = @import("freetype.zig").RenderMode;
const Matrix = @import("types.zig").Matrix;
const Outline = @import("image.zig").Outline;
const GlyphFormat = @import("image.zig").GlyphFormat;
const Vector = @import("image.zig").Vector;
const GlyphMetrics = @import("image.zig").GlyphMetrics;
const Bitmap = @import("image.zig").Bitmap;
const GlyphSlot = @This();
@ -14,40 +19,49 @@ pub const SubGlyphInfo = struct {
flags: u32,
arg1: i32,
arg2: i32,
transform: types.Matrix,
transform: Matrix,
};
handle: c.FT_GlyphSlot,
pub fn init(handle: c.FT_GlyphSlot) GlyphSlot {
return GlyphSlot{ .handle = handle };
pub fn library(self: GlyphSlot) Library {
return .{ .handle = self.handle.*.library };
}
pub fn render(self: GlyphSlot, render_mode: types.RenderMode) Error!void {
return intToError(c.FT_Render_Glyph(self.handle, @enumToInt(render_mode)));
pub fn face(self: GlyphSlot) Face {
return .{ .handle = self.handle.*.face };
}
pub fn subGlyphInfo(self: GlyphSlot, sub_index: u32) Error!SubGlyphInfo {
var info = std.mem.zeroes(SubGlyphInfo);
try intToError(c.FT_Get_SubGlyph_Info(self.handle, sub_index, &info.index, &info.flags, &info.arg1, &info.arg2, @ptrCast(*c.FT_Matrix, &info.transform)));
return info;
pub fn next(self: GlyphSlot) GlyphSlot {
return .{ .handle = self.handle.*.next };
}
pub fn glyph(self: GlyphSlot) Error!Glyph {
var out = std.mem.zeroes(c.FT_Glyph);
try intToError(c.FT_Get_Glyph(self.handle, &out));
return Glyph.init(out);
pub fn glyphIndex(self: GlyphSlot) u32 {
return self.handle.*.glyph_index;
}
pub fn outline(self: GlyphSlot) ?Outline {
return if (self.format() == .outline)
Outline.init(&self.handle.*.outline)
else
null;
pub fn metrics(self: GlyphSlot) GlyphMetrics {
return self.handle.*.metrics;
}
pub fn linearHoriAdvance(self: GlyphSlot) i32 {
return @intCast(i32, self.handle.*.linearHoriAdvance);
}
pub fn linearVertAdvance(self: GlyphSlot) i32 {
return @intCast(i32, self.handle.*.linearVertAdvance);
}
pub fn advance(self: GlyphSlot) Vector {
return self.handle.*.advance;
}
pub fn format(self: GlyphSlot) GlyphFormat {
return @intToEnum(GlyphFormat, self.handle.*.format);
}
pub fn bitmap(self: GlyphSlot) Bitmap {
return Bitmap.init(self.handle.*.bitmap);
return .{ .handle = self.handle.*.bitmap };
}
pub fn bitmapLeft(self: GlyphSlot) i32 {
@ -58,22 +72,30 @@ pub fn bitmapTop(self: GlyphSlot) i32 {
return self.handle.*.bitmap_top;
}
pub fn linearHoriAdvance(self: GlyphSlot) i64 {
return self.handle.*.linearHoriAdvance;
pub fn outline(self: GlyphSlot) ?Outline {
return if (self.format() == .outline) .{ .handle = &self.handle.*.outline } else null;
}
pub fn linearVertAdvance(self: GlyphSlot) i64 {
return self.handle.*.linearVertAdvance;
pub fn lsbDelta(self: GlyphSlot) i32 {
return @intCast(i32, self.handle.*.lsb_delta);
}
pub fn advance(self: GlyphSlot) types.Vector {
return @ptrCast(*types.Vector, &self.handle.*.advance).*;
pub fn rsbDelta(self: GlyphSlot) i32 {
return @intCast(i32, self.handle.*.rsb_delta);
}
pub fn format(self: GlyphSlot) Glyph.GlyphFormat {
return @intToEnum(Glyph.GlyphFormat, self.handle.*.format);
pub fn render(self: GlyphSlot, render_mode: RenderMode) Error!void {
return intToError(c.FT_Render_Glyph(self.handle, @enumToInt(render_mode)));
}
pub fn metrics(self: GlyphSlot) Glyph.GlyphMetrics {
return self.handle.*.metrics;
pub fn subGlyphInfo(self: GlyphSlot, sub_index: u32) Error!SubGlyphInfo {
var info: SubGlyphInfo = undefined;
try intToError(c.FT_Get_SubGlyph_Info(self.handle, sub_index, &info.index, &info.flags, &info.arg1, &info.arg2, &info.transform));
return info;
}
pub fn getGlyph(self: GlyphSlot) Error!Glyph {
var res: c.FT_Glyph = undefined;
try intToError(c.FT_Get_Glyph(self.handle, &res));
return Glyph{ .handle = res };
}

View file

@ -1,26 +1,26 @@
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 intToError = @import("error.zig").intToError;
const Error = @import("error.zig").Error;
const Stroker = @import("Stroker.zig");
const Face = @import("freetype.zig").Face;
const OpenArgs = @import("freetype.zig").OpenArgs;
const LcdFilter = @import("lcdfilter.zig").LcdFilter;
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,
pub const Version = struct {
major: i32,
minor: i32,
patch: i32,
};
handle: c.FT_Library,
pub fn init() Error!Library {
var ft = std.mem.zeroes(Library);
try intToError(c.FT_Init_FreeType(&ft.handle));
return ft;
var lib = Library{ .handle = undefined };
try intToError(c.FT_Init_FreeType(&lib.handle));
return lib;
}
pub fn deinit(self: Library) void {
@ -43,16 +43,27 @@ pub fn newFaceMemory(self: Library, bytes: []const u8, face_index: i32) Error!Fa
}, face_index);
}
pub fn openFace(self: Library, args: types.OpenArgs, face_index: i32) Error!Face {
var face = std.mem.zeroes(c.FT_Face);
try intToError(c.FT_Open_Face(self.handle, &args.toCInterface(), face_index, &face));
return Face.init(face);
pub fn openFace(self: Library, args: OpenArgs, face_index: i32) Error!Face {
var f: c.FT_Face = undefined;
try intToError(c.FT_Open_Face(self.handle, &args.cast(), face_index, &f));
return Face{ .handle = f };
}
pub fn version(self: Library) Version {
var v: Version = undefined;
c.FT_Library_Version(
self.handle,
&v.major,
&v.minor,
&v.patch,
);
return v;
}
pub fn newStroker(self: Library) Error!Stroker {
var stroker = std.mem.zeroes(c.FT_Stroker);
try intToError(c.FT_Stroker_New(self.handle, &stroker));
return Stroker.init(stroker);
var s: c.FT_Stroker = undefined;
try intToError(c.FT_Stroker_New(self.handle, &s));
return Stroker{ .handle = s };
}
pub fn setLcdFilter(self: Library, lcd_filter: LcdFilter) Error!void {

View file

@ -1,19 +1,15 @@
const std = @import("std");
const c = @import("c.zig");
const types = @import("types.zig");
const Glyph = @import("Glyph.zig");
const Error = @import("error.zig").Error;
const intToError = @import("error.zig").intToError;
const errorToInt = @import("error.zig").errorToInt;
const Error = @import("error.zig").Error;
const Matrix = @import("types.zig").Matrix;
const BBox = @import("types.zig").BBox;
const Vector = @import("image.zig").Vector;
const Outline = @This();
handle: *c.FT_Outline,
pub fn init(handle: *c.FT_Outline) Outline {
return Outline{ .handle = handle };
}
pub fn numPoints(self: Outline) u15 {
return @intCast(u15, self.handle.*.n_points);
}
@ -22,8 +18,8 @@ pub fn numContours(self: Outline) u15 {
return @intCast(u15, self.handle.*.n_contours);
}
pub fn points(self: Outline) []const types.Vector {
return @ptrCast([]types.Vector, self.handle.*.points[0..self.numPoints()]);
pub fn points(self: Outline) []const Vector {
return self.handle.*.points[0..self.numPoints()];
}
pub fn tags(self: Outline) []const u8 {
@ -38,25 +34,24 @@ pub fn check(self: Outline) Error!void {
try intToError(c.FT_Outline_Check(self.handle));
}
pub fn transform(self: Outline, matrix: ?types.Matrix) void {
var m = matrix orelse std.mem.zeroes(types.Matrix);
c.FT_Outline_Transform(self.handle, @ptrCast(*c.FT_Matrix, &m));
pub fn transform(self: Outline, matrix: ?Matrix) void {
c.FT_Outline_Transform(self.handle, if (matrix) |m| &m else null);
}
pub fn bbox(self: Outline) Error!types.BBox {
var res = std.mem.zeroes(types.BBox);
try intToError(c.FT_Outline_Get_BBox(self.handle, @ptrCast(*c.FT_BBox, &res)));
return res;
pub fn bbox(self: Outline) Error!BBox {
var b: BBox = undefined;
try intToError(c.FT_Outline_Get_BBox(self.handle, &b));
return b;
}
pub fn OutlineFuncs(comptime Context: type) type {
return struct {
move_to: fn (ctx: Context, to: types.Vector) Error!void,
line_to: fn (ctx: Context, to: types.Vector) Error!void,
conic_to: fn (ctx: Context, control: types.Vector, to: types.Vector) Error!void,
cubic_to: fn (ctx: Context, control_0: types.Vector, control_1: types.Vector, to: types.Vector) Error!void,
shift: c_int,
delta: isize,
move_to: fn (ctx: Context, to: Vector) Error!void,
line_to: fn (ctx: Context, to: Vector) Error!void,
conic_to: fn (ctx: Context, control: Vector, to: Vector) Error!void,
cubic_to: fn (ctx: Context, control_0: Vector, control_1: Vector, to: Vector) Error!void,
shift: i32,
delta: i32,
};
}
@ -70,8 +65,8 @@ pub fn OutlineFuncsWrapper(comptime Context: type) type {
return @ptrCast(*Self, @alignCast(@alignOf(Self), ptr));
}
fn castVec(vec: [*c]const c.FT_Vector) types.Vector {
return @intToPtr(*types.Vector, @ptrToInt(vec)).*;
fn castVec(vec: [*c]const c.FT_Vector) Vector {
return @intToPtr(*Vector, @ptrToInt(vec)).*;
}
pub fn move_to(to: [*c]const c.FT_Vector, ctx: ?*anyopaque) callconv(.C) c_int {
@ -130,7 +125,7 @@ pub fn decompose(self: Outline, ctx: anytype, callbacks: OutlineFuncs(@TypeOf(ct
var wrapper = OutlineFuncsWrapper(@TypeOf(ctx)){ .ctx = ctx, .callbacks = callbacks };
try intToError(c.FT_Outline_Decompose(
self.handle,
&c.FT_Outline_Funcs{
&.{
.move_to = @TypeOf(wrapper).move_to,
.line_to = @TypeOf(wrapper).line_to,
.conic_to = @TypeOf(wrapper).conic_to,

View file

@ -1,15 +1,14 @@
const c = @import("c.zig");
const Error = @import("error.zig").Error;
const intToError = @import("error.zig").intToError;
const Stroker = @This();
pub const Stroker = @This();
pub const StrokerLineCap = enum(u2) {
pub const LineCap = 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) {
pub const LineJoin = enum(u2) {
round = c.FT_STROKER_LINEJOIN_ROUND,
bevel = c.FT_STROKER_LINEJOIN_BEVEL,
miterVariable = c.FT_STROKER_LINEJOIN_MITER_VARIABLE,
@ -18,11 +17,7 @@ pub const StrokerLineJoin = enum(u2) {
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 {
pub fn set(self: Stroker, radius: i32, line_cap: LineCap, line_join: LineJoin, miter_limit: i32) void {
c.FT_Stroker_Set(self.handle, radius, @enumToInt(line_cap), @enumToInt(line_join), miter_limit);
}

View file

@ -1,8 +1,10 @@
pub usingnamespace @cImport({
@cInclude("freetype/freetype.h");
@cInclude("freetype/ftbbox.h");
@cInclude("freetype/ftcolor.h");
@cInclude("freetype/ftlcdfil.h");
@cInclude("freetype/ftmodapi.h");
@cInclude("freetype/ftsizes.h");
@cInclude("freetype/ftstroke.h");
@cInclude("freetype/ftsystem.h");
@cInclude("ft2build.h");

176
freetype/src/color.zig Normal file
View file

@ -0,0 +1,176 @@
const c = @import("c.zig");
const utils = @import("utils.zig");
const Face = @import("freetype.zig").Face;
pub const Color = c.FT_Color;
pub const LayerIterator = c.FT_LayerIterator;
pub const ColorStopIterator = c.FT_ColorStopIterator;
pub const ColorIndex = c.FT_ColorIndex;
pub const ColorStop = c.FT_ColorStop;
pub const ColorLine = c.FT_ColorLine;
pub const Affine23 = c.FT_Affine23;
pub const OpaquePaint = c.FT_OpaquePaint;
pub const PaintColrLayers = c.FT_PaintColrLayers;
pub const PaintSolid = c.FT_PaintSolid;
pub const PaintLinearGradient = c.FT_PaintLinearGradient;
pub const PaintRadialGradient = c.FT_PaintRadialGradient;
pub const PaintSweepGradient = c.FT_PaintSweepGradient;
pub const PaintGlyph = c.FT_PaintGlyph;
pub const PaintColrGlyph = c.FT_PaintColrGlyph;
pub const PaintTransform = c.FT_PaintTransform;
pub const PaintTranslate = c.FT_PaintTranslate;
pub const PaintScale = c.FT_PaintScale;
pub const PaintRotate = c.FT_PaintRotate;
pub const PaintSkew = c.FT_PaintSkew;
pub const PaintComposite = c.FT_PaintComposite;
pub const ClipBox = c.FT_ClipBox;
pub const RootTransform = enum(u1) {
include_root_transform = c.FT_COLOR_INCLUDE_ROOT_TRANSFORM,
no_root_transform = c.FT_COLOR_NO_ROOT_TRANSFORM,
};
pub const PaintExtend = enum(u2) {
pad = c.FT_COLR_PAINT_EXTEND_PAD,
repeat = c.FT_COLR_PAINT_EXTEND_REPEAT,
reflect = c.FT_COLR_PAINT_EXTEND_REFLECT,
};
pub const PaintFormat = enum(u8) {
color_layers = c.FT_COLR_PAINTFORMAT_COLR_LAYERS,
solid = c.FT_COLR_PAINTFORMAT_SOLID,
linear_gradient = c.FT_COLR_PAINTFORMAT_LINEAR_GRADIENT,
radial_gradient = c.FT_COLR_PAINTFORMAT_RADIAL_GRADIENT,
sweep_gradient = c.FT_COLR_PAINTFORMAT_SWEEP_GRADIENT,
glyph = c.FT_COLR_PAINTFORMAT_GLYPH,
color_glyph = c.FT_COLR_PAINTFORMAT_COLR_GLYPH,
transform = c.FT_COLR_PAINTFORMAT_TRANSFORM,
translate = c.FT_COLR_PAINTFORMAT_TRANSLATE,
scale = c.FT_COLR_PAINTFORMAT_SCALE,
rotate = c.FT_COLR_PAINTFORMAT_ROTATE,
skew = c.FT_COLR_PAINTFORMAT_SKEW,
composite = c.FT_COLR_PAINTFORMAT_COMPOSITE,
};
pub const CompositeMode = enum(u5) {
clear = c.FT_COLR_COMPOSITE_CLEAR,
src = c.FT_COLR_COMPOSITE_SRC,
dest = c.FT_COLR_COMPOSITE_DEST,
src_over = c.FT_COLR_COMPOSITE_SRC_OVER,
dest_over = c.FT_COLR_COMPOSITE_DEST_OVER,
src_in = c.FT_COLR_COMPOSITE_SRC_IN,
dest_in = c.FT_COLR_COMPOSITE_DEST_IN,
src_out = c.FT_COLR_COMPOSITE_SRC_OUT,
dest_out = c.FT_COLR_COMPOSITE_DEST_OUT,
src_atop = c.FT_COLR_COMPOSITE_SRC_ATOP,
dest_atop = c.FT_COLR_COMPOSITE_DEST_ATOP,
xor = c.FT_COLR_COMPOSITE_XOR,
plus = c.FT_COLR_COMPOSITE_PLUS,
screen = c.FT_COLR_COMPOSITE_SCREEN,
overlay = c.FT_COLR_COMPOSITE_OVERLAY,
darken = c.FT_COLR_COMPOSITE_DARKEN,
lighten = c.FT_COLR_COMPOSITE_LIGHTEN,
color_dodge = c.FT_COLR_COMPOSITE_COLOR_DODGE,
color_burn = c.FT_COLR_COMPOSITE_COLOR_BURN,
hard_light = c.FT_COLR_COMPOSITE_HARD_LIGHT,
soft_light = c.FT_COLR_COMPOSITE_SOFT_LIGHT,
difference = c.FT_COLR_COMPOSITE_DIFFERENCE,
exclusion = c.FT_COLR_COMPOSITE_EXCLUSION,
multiply = c.FT_COLR_COMPOSITE_MULTIPLY,
hsl_hue = c.FT_COLR_COMPOSITE_HSL_HUE,
hsl_saturation = c.FT_COLR_COMPOSITE_HSL_SATURATION,
hsl_color = c.FT_COLR_COMPOSITE_HSL_COLOR,
hsl_luminosity = c.FT_COLR_COMPOSITE_HSL_LUMINOSITY,
};
pub const Paint = union(PaintFormat) {
color_layers: PaintColrLayers,
glyph: PaintGlyph,
solid: PaintSolid,
linear_gradient: PaintLinearGradient,
radial_gradient: PaintRadialGradient,
sweep_gradient: PaintSweepGradient,
transform: PaintTransform,
translate: PaintTranslate,
scale: PaintScale,
rotate: PaintRotate,
skew: PaintSkew,
composite: PaintComposite,
color_glyph: PaintColrGlyph,
};
pub const PaletteData = struct {
handle: c.FT_Palette_Data,
pub fn numPalettes(self: PaletteData) u16 {
return self.handle.num_palettes;
}
pub fn paletteNameIDs(self: PaletteData) ?[]const u16 {
return @ptrCast(?[]const u16, self.handle.palette_name_ids[0..self.numPalettes()]);
}
pub fn paletteFlags(self: PaletteData) ?[]const u16 {
return @ptrCast(?[]const u16, self.handle.palette_flags[0..self.numPalettes()]);
}
pub fn paletteFlag(self: PaletteData, index: usize) PaletteFlags {
return PaletteFlags.from(@intCast(u2, self.handle.*.palette_flags[index]));
}
pub fn numPaletteEntries(self: PaletteData) u16 {
return self.handle.num_palette_entries;
}
pub fn paletteEntryNameIDs(self: PaletteData) ?[]const u16 {
return @ptrCast(?[]const u16, self.handle.palette_entry_name_ids[0..self.numPaletteEntries()]);
}
};
pub const PaletteFlags = packed struct {
for_light_background: bool = false,
for_dark_background: bool = false,
pub const Flag = enum(u2) {
for_light_background = c.FT_PALETTE_FOR_LIGHT_BACKGROUND,
for_dark_background = c.FT_PALETTE_FOR_DARK_BACKGROUND,
};
pub fn from(bits: u2) PaletteFlags {
return utils.bitFieldsToStruct(PaletteFlags, Flag, bits);
}
pub fn to(flags: PaletteFlags) u2 {
return utils.structToBitFields(u2, PaletteFlags, Flag, flags);
}
};
pub const GlyphLayersIterator = struct {
face: Face,
glyph_index: u32,
layer_glyph_index: u32,
layer_color_index: u32,
iterator: LayerIterator,
pub fn init(face: Face, glyph_index: u32) GlyphLayersIterator {
var iterator: LayerIterator = undefined;
iterator.p = null;
return .{
.face = face,
.glyph_index = glyph_index,
.layer_glyph_index = 0,
.layer_color_index = 0,
.iterator = iterator,
};
}
pub fn next(self: *GlyphLayersIterator) bool {
return if (c.FT_Get_Color_Glyph_Layer(
self.face.handle,
self.glyph_index,
&self.layer_glyph_index,
&self.layer_color_index,
&self.iterator,
) == 0) false else true;
}
};

288
freetype/src/freetype.zig Normal file
View file

@ -0,0 +1,288 @@
const std = @import("std");
const c = @import("c.zig");
const utils = @import("utils.zig");
const intToError = @import("error.zig").intToError;
const Error = @import("error.zig").Error;
const Generic = @import("types.zig").Generic;
pub const Library = @import("Library.zig");
pub const Face = @import("Face.zig");
pub const GlyphSlot = @import("GlyphSlot.zig");
pub const SizeRequest = c.FT_Size_RequestRec;
pub const BitmapSize = c.FT_Bitmap_Size;
pub const CharMap = c.FT_CharMapRec;
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 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 SizeRequestType = enum(u3) {
nominal = c.FT_SIZE_REQUEST_TYPE_NOMINAL,
real_dim = c.FT_SIZE_REQUEST_TYPE_REAL_DIM,
bbox = c.FT_SIZE_REQUEST_TYPE_BBOX,
cell = c.FT_SIZE_REQUEST_TYPE_CELL,
scales = c.FT_SIZE_REQUEST_TYPE_SCALES,
max = c.FT_SIZE_REQUEST_TYPE_MAX,
};
pub const Encoding = enum(u31) {
none = c.FT_ENCODING_NONE,
ms_symbol = c.FT_ENCODING_MS_SYMBOL,
unicode = c.FT_ENCODING_UNICODE,
sjis = c.FT_ENCODING_SJIS,
prc = c.FT_ENCODING_PRC,
big5 = c.FT_ENCODING_BIG5,
wansung = c.FT_ENCODING_WANSUNG,
johab = c.FT_ENCODING_JOHAB,
adobe_standard = c.FT_ENCODING_ADOBE_STANDARD,
adobe_expert = c.FT_ENCODING_ADOBE_EXPERT,
adobe_custom = c.FT_ENCODING_ADOBE_CUSTOM,
adobe_latin_1 = c.FT_ENCODING_ADOBE_LATIN_1,
old_latin_2 = c.FT_ENCODING_OLD_LATIN_2,
apple_roman = c.FT_ENCODING_APPLE_ROMAN,
};
pub const Size = struct {
handle: c.FT_Size,
pub fn face(self: Size) Face {
return Face{ .handle = self.handle.*.face };
}
pub fn generic(self: Size) Generic {
return self.handle.*.generic;
}
pub fn metrics(self: Size) SizeMetrics {
return self.handle.*.metrics;
}
pub fn activate(self: Size) Error!void {
try intToError(c.FT_Activate_Size(self.handle));
}
pub fn deinit(self: Size) void {
c.FT_Done_Size(self.handle);
}
};
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 from(bits: u21) LoadFlags {
return utils.bitFieldsToStruct(LoadFlags, Flag, bits);
}
pub fn cast(flags: LoadFlags) u21 {
return utils.structToBitFields(u21, Flag, flags);
}
};
pub const FaceFlags = packed struct {
scalable: bool = false,
fixed_sizes: bool = false,
fixed_width: bool = false,
sfnt: bool = false,
horizontal: bool = false,
vertical: bool = false,
kerning: bool = false,
fast_glyphs: bool = false,
multiple_masters: bool = false,
glyph_names: bool = false,
external_stream: bool = false,
hinter: bool = false,
cid_keyed: bool = false,
tricky: bool = false,
color: bool = false,
variation: bool = false,
svg: bool = false,
sbix: bool = false,
sbix_overlay: bool = false,
pub const Flag = enum(u19) {
scalable = c.FT_FACE_FLAG_SCALABLE,
fixed_sizes = c.FT_FACE_FLAG_FIXED_SIZES,
fixed_width = c.FT_FACE_FLAG_FIXED_WIDTH,
sfnt = c.FT_FACE_FLAG_SFNT,
horizontal = c.FT_FACE_FLAG_HORIZONTAL,
vertical = c.FT_FACE_FLAG_VERTICAL,
kerning = c.FT_FACE_FLAG_KERNING,
fast_glyphs = c.FT_FACE_FLAG_FAST_GLYPHS,
multiple_masters = c.FT_FACE_FLAG_MULTIPLE_MASTERS,
glyph_names = c.FT_FACE_FLAG_GLYPH_NAMES,
external_stream = c.FT_FACE_FLAG_EXTERNAL_STREAM,
hinter = c.FT_FACE_FLAG_HINTER,
cid_keyed = c.FT_FACE_FLAG_CID_KEYED,
tricky = c.FT_FACE_FLAG_TRICKY,
color = c.FT_FACE_FLAG_COLOR,
variation = c.FT_FACE_FLAG_VARIATION,
svg = c.FT_FACE_FLAG_SVG,
sbix = c.FT_FACE_FLAG_SBIX,
sbix_overlay = c.FT_FACE_FLAG_SBIX_OVERLAY,
};
pub fn from(bits: u19) FaceFlags {
return utils.bitFieldsToStruct(FaceFlags, Flag, bits);
}
pub fn cast(self: FaceFlags) u19 {
return utils.structToBitFields(u19, Flag, self);
}
};
pub const FSType = packed struct {
installable_embedding: bool = false,
restriced_license_embedding: bool = false,
preview_and_print_embedding: bool = false,
editable_embedding: bool = false,
no_subsetting: bool = false,
bitmap_embedding_only: bool = false,
pub const Flag = enum(u10) {
installable_embedding = c.FT_FSTYPE_INSTALLABLE_EMBEDDING,
restriced_license_embedding = c.FT_FSTYPE_RESTRICTED_LICENSE_EMBEDDING,
preview_and_print_embedding = c.FT_FSTYPE_PREVIEW_AND_PRINT_EMBEDDING,
editable_embedding = c.FT_FSTYPE_EDITABLE_EMBEDDING,
no_subsetting = c.FT_FSTYPE_NO_SUBSETTING,
bitmap_embedding_only = c.FT_FSTYPE_BITMAP_EMBEDDING_ONLY,
};
pub fn from(bits: u10) FSType {
return utils.bitFieldsToStruct(FSType, Flag, bits);
}
pub fn cast(flags: FSType) u10 {
return utils.structToBitFields(u10, FSType, Flag, flags);
}
};
pub const StyleFlags = packed struct {
italic: bool = false,
bold: bool = false,
pub const Flag = enum(u2) {
italic = c.FT_STYLE_FLAG_ITALIC,
bold = c.FT_STYLE_FLAG_BOLD,
};
pub fn from(bits: u2) StyleFlags {
return utils.bitFieldsToStruct(StyleFlags, Flag, bits);
}
pub fn cast(flags: StyleFlags) u2 {
return utils.structToBitFields(u2, StyleFlags, Flag, flags);
}
};
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 from(bits: u5) OpenFlags {
return utils.bitFieldsToStruct(OpenFlags, Flag, bits);
}
pub fn cast(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 cast(self: OpenArgs) c.FT_Open_Args {
var oa: c.FT_Open_Args = undefined;
oa.flags = self.flags.cast();
switch (self.data) {
.memory => |d| {
oa.memory_base = d.ptr;
oa.memory_size = @intCast(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;
}
};
pub fn getCharmapIndex(self: [*c]CharMap) ?u32 {
const i = c.FT_Get_Charmap_Index(self);
return if (i == -1) null else @intCast(u32, i);
}

52
freetype/src/image.zig Normal file
View file

@ -0,0 +1,52 @@
const std = @import("std");
const c = @import("c.zig");
pub const Outline = @import("Outline.zig");
pub const Vector = c.FT_Vector;
pub const GlyphMetrics = c.FT_Glyph_Metrics;
pub const PixelMode = enum(u3) {
none = c.FT_PIXEL_MODE_NONE,
mono = c.FT_PIXEL_MODE_MONO,
gray = c.FT_PIXEL_MODE_GRAY,
gray2 = c.FT_PIXEL_MODE_GRAY2,
gray4 = c.FT_PIXEL_MODE_GRAY4,
lcd = c.FT_PIXEL_MODE_LCD,
lcd_v = c.FT_PIXEL_MODE_LCD_V,
bgra = c.FT_PIXEL_MODE_BGRA,
};
pub const GlyphFormat = enum(u32) {
none = c.FT_GLYPH_FORMAT_NONE,
composite = c.FT_GLYPH_FORMAT_COMPOSITE,
bitmap = c.FT_GLYPH_FORMAT_BITMAP,
outline = c.FT_GLYPH_FORMAT_OUTLINE,
plotter = c.FT_GLYPH_FORMAT_PLOTTER,
svg = c.FT_GLYPH_FORMAT_SVG,
};
pub const Bitmap = struct {
handle: c.FT_Bitmap,
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 @intToEnum(PixelMode, self.handle.pixel_mode);
}
pub fn buffer(self: Bitmap) []const u8 {
const buffer_size = std.math.absCast(self.pitch()) * self.rows();
return self.handle.buffer[0..buffer_size];
}
};

View file

@ -0,0 +1,8 @@
const c = @import("c.zig");
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,
};

View file

@ -1,26 +1,38 @@
pub const Library = @import("Library.zig");
pub const Face = @import("Face.zig");
pub const GlyphSlot = @import("GlyphSlot.zig");
pub usingnamespace @import("freetype.zig");
pub usingnamespace @import("types.zig");
pub usingnamespace @import("image.zig");
pub usingnamespace @import("color.zig");
pub usingnamespace @import("lcdfilter.zig");
pub const c = @import("c.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");
const std = @import("std");
fn refLiterallyAllDecls(comptime T: type) void {
switch (@typeInfo(T)) {
.Struct, .Union, .Opaque, .Enum => {
inline for (comptime std.meta.declarations(T)) |decl| {
if (decl.is_pub) {
refLiterallyAllDecls(@TypeOf(@field(T, decl.name)));
std.testing.refAllDecls(T);
}
}
},
else => {},
}
}
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"));
refLiterallyAllDecls(@This());
refLiterallyAllDecls(@import("color.zig"));
refLiterallyAllDecls(@import("error.zig"));
refLiterallyAllDecls(@import("utils.zig"));
refLiterallyAllDecls(@import("Face.zig"));
refLiterallyAllDecls(@import("GlyphSlot.zig"));
refLiterallyAllDecls(@import("Library.zig"));
refLiterallyAllDecls(@import("Outline.zig"));
refLiterallyAllDecls(Glyph);
refLiterallyAllDecls(Stroker);
}

View file

@ -1,77 +1,5 @@
const std = @import("std");
const c = @import("c.zig");
const utils = @import("utils.zig");
pub const Vector = extern struct {
x: c_long,
y: c_long,
};
pub const Matrix = extern struct {
xx: c_long,
xy: c_long,
yx: c_long,
yy: c_long,
};
pub const BBox = extern struct {
xMin: c_long,
yMin: c_long,
xMax: c_long,
yMax: c_long,
};
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 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;
}
};
pub const Matrix = c.FT_Matrix;
pub const Generic = c.FT_Generic;
pub const BBox = c.FT_BBox;

View file

@ -1,11 +1,8 @@
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| {
inline for (comptime std.meta.fieldNames(EnumDataType)) |field_name| {
if (@field(flags, field_name)) {
value |= @enumToInt(@field(EnumDataType, field_name));
}
@ -14,8 +11,8 @@ pub fn structToBitFields(comptime IntType: type, comptime EnumDataType: type, fl
}
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| {
var value = std.mem.zeroes(StructType);
inline for (comptime std.meta.fieldNames(EnumDataType)) |field_name| {
if (flags & (@enumToInt(@field(EnumDataType, field_name))) != 0) {
@field(value, field_name) = true;
}
@ -36,13 +33,13 @@ const TestStruct = packed struct {
};
test "struct fields to bit fields" {
try testing.expectEqual(@as(u16, (1 << 1) | (1 << 3)), structToBitFields(u16, TestEnum, TestStruct{
try std.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{}));
try std.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)));
try std.testing.expectEqual(TestStruct{ .filed_1 = true, .filed_2 = true, .filed_3 = false }, bitFieldsToStruct(TestStruct, TestEnum, (1 << 1) | (1 << 2)));
}

View file

@ -1,3 +1,4 @@
const testing = @import("std").testing;
const freetype = @import("freetype");
const firasnas_font_path = "upstream/assets/FiraSans-Regular.ttf";
@ -19,7 +20,7 @@ test "new stroker" {
}
test "set lcd filter" {
if (@hasDecl(freetype.C, "FT_CONFIG_OPTION_SUBPIXEL_RENDERING")) {
if (@hasDecl(freetype.c, "FT_CONFIG_OPTION_SUBPIXEL_RENDERING")) {
const lib = try freetype.Library.init();
try lib.setLcdFilter(.default);
} else {
@ -52,3 +53,26 @@ test "attach from memory" {
const file = @embedFile("../upstream/assets/DejaVuSans.pfm");
try face.attachMemory(file);
}
test "charmap iterator" {
const lib = try freetype.Library.init();
const face = try lib.newFace(firasnas_font_path, 0);
var iterator = face.getCharmapIterator();
var old_char: usize = 0;
while (iterator.next()) |c| {
try testing.expect(old_char != c);
old_char = c;
}
}
test "get name index" {
const lib = try freetype.Library.init();
const face = try lib.newFace(firasnas_font_path, 0);
try testing.expectEqual(@as(u32, 1120), face.getNameIndex("summation").?);
}
test "get index name" {
const lib = try freetype.Library.init();
const face = try lib.newFace(firasnas_font_path, 0);
try testing.expectEqualStrings("summation", try face.getGlyphName(1120));
}