diff --git a/examples/gkurve/text.zig b/examples/gkurve/text.zig index c21ba6dc..dcb1b92f 100644 --- a/examples/gkurve/text.zig +++ b/examples/gkurve/text.zig @@ -15,7 +15,7 @@ const Vec4 = @Vector(4, f32); const GlyphInfo = struct { uv_data: UVData, - metrics: ft.Glyph.GlyphMetrics, + metrics: ft.GlyphMetrics, }; face: ft.Face, @@ -63,7 +63,7 @@ fn write(ctx: WriterContext, bytes: []const u8) ft.Error!usize { switch (char) { '\n' => { offset[0] = 0; - offset[1] -= @intToFloat(f32, ctx.label.face.sizeMetrics().?.height >> 6); + offset[1] -= @intToFloat(f32, ctx.label.face.size().metrics().height >> 6); }, ' ' => { const v = ctx.label.char_map.getOrPut(char) catch unreachable; @@ -73,7 +73,7 @@ fn write(ctx: WriterContext, bytes: []const u8) ft.Error!usize { const glyph = ctx.label.face.glyph; v.value_ptr.* = GlyphInfo{ .uv_data = undefined, - .metrics = glyph.metrics(), + .metrics = glyph().metrics(), }; } offset[0] += @intToFloat(f32, v.value_ptr.metrics.horiAdvance >> 6); @@ -83,7 +83,7 @@ fn write(ctx: WriterContext, bytes: []const u8) ft.Error!usize { if (!v.found_existing) { try ctx.label.face.setCharSize(ctx.label.size * 64, 0, 50, 0); try ctx.label.face.loadChar(char, .{ .render = true }); - const glyph = ctx.label.face.glyph; + const glyph = ctx.label.face.glyph(); const glyph_bitmap = glyph.bitmap(); const glyph_width = glyph_bitmap.width(); const glyph_height = glyph_bitmap.rows(); diff --git a/freetype/build.zig b/freetype/build.zig index 54441b00..dce77e2b 100644 --- a/freetype/build.zig +++ b/freetype/build.zig @@ -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); } diff --git a/freetype/examples/glyph-to-svg.zig b/freetype/examples/glyph-to-svg.zig index 18a310c5..637114a4 100644 --- a/freetype/examples/glyph-to-svg.zig +++ b/freetype/examples/glyph-to-svg.zig @@ -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, 'ë')); } diff --git a/freetype/examples/single-glyph.zig b/freetype/examples/single-glyph.zig index f2e72b27..cd5340a7 100644 --- a/freetype/examples/single-glyph.zig +++ b/freetype/examples/single-glyph.zig @@ -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 => '#', diff --git a/freetype/src/Bitmap.zig b/freetype/src/Bitmap.zig deleted file mode 100644 index cbfe827b..00000000 --- a/freetype/src/Bitmap.zig +++ /dev/null @@ -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]; -} diff --git a/freetype/src/BitmapGlyph.zig b/freetype/src/BitmapGlyph.zig deleted file mode 100644 index 2104378a..00000000 --- a/freetype/src/BitmapGlyph.zig +++ /dev/null @@ -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); -} diff --git a/freetype/src/Face.zig b/freetype/src/Face.zig index c4162676..1f7d7b6f 100644 --- a/freetype/src/Face.zig +++ b/freetype/src/Face.zig @@ -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; -} diff --git a/freetype/src/Glyph.zig b/freetype/src/Glyph.zig index 8211a4ce..474fb6ce 100644 --- a/freetype/src/Glyph.zig +++ b/freetype/src/Glyph.zig @@ -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 }; + } +}; diff --git a/freetype/src/GlyphSlot.zig b/freetype/src/GlyphSlot.zig index 9da95813..2815b735 100644 --- a/freetype/src/GlyphSlot.zig +++ b/freetype/src/GlyphSlot.zig @@ -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 }; } diff --git a/freetype/src/Library.zig b/freetype/src/Library.zig index 2387dbb1..7532e304 100644 --- a/freetype/src/Library.zig +++ b/freetype/src/Library.zig @@ -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 { diff --git a/freetype/src/Outline.zig b/freetype/src/Outline.zig index 2cb0b5b5..c54eba60 100644 --- a/freetype/src/Outline.zig +++ b/freetype/src/Outline.zig @@ -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, diff --git a/freetype/src/Stroker.zig b/freetype/src/Stroker.zig index f3567fc0..07d23d41 100644 --- a/freetype/src/Stroker.zig +++ b/freetype/src/Stroker.zig @@ -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); } diff --git a/freetype/src/c.zig b/freetype/src/c.zig index 0d077a1d..0a407038 100644 --- a/freetype/src/c.zig +++ b/freetype/src/c.zig @@ -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"); diff --git a/freetype/src/color.zig b/freetype/src/color.zig new file mode 100644 index 00000000..86887666 --- /dev/null +++ b/freetype/src/color.zig @@ -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; + } +}; diff --git a/freetype/src/freetype.zig b/freetype/src/freetype.zig new file mode 100644 index 00000000..fc777465 --- /dev/null +++ b/freetype/src/freetype.zig @@ -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); +} diff --git a/freetype/src/image.zig b/freetype/src/image.zig new file mode 100644 index 00000000..03a271c5 --- /dev/null +++ b/freetype/src/image.zig @@ -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]; + } +}; diff --git a/freetype/src/lcdfilter.zig b/freetype/src/lcdfilter.zig new file mode 100644 index 00000000..2928acf3 --- /dev/null +++ b/freetype/src/lcdfilter.zig @@ -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, +}; diff --git a/freetype/src/main.zig b/freetype/src/main.zig index 3b466638..a6f3b65e 100644 --- a/freetype/src/main.zig +++ b/freetype/src/main.zig @@ -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); } diff --git a/freetype/src/types.zig b/freetype/src/types.zig index 79255ce0..cec8e08b 100644 --- a/freetype/src/types.zig +++ b/freetype/src/types.zig @@ -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; diff --git a/freetype/src/utils.zig b/freetype/src/utils.zig index 5b3dc1fe..e377a72d 100644 --- a/freetype/src/utils.zig +++ b/freetype/src/utils.zig @@ -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))); } diff --git a/freetype/test/main.zig b/freetype/test/main.zig index bd4bf6be..55b65671 100644 --- a/freetype/test/main.zig +++ b/freetype/test/main.zig @@ -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)); +}