diff --git a/freetype/.github/workflows/ci.yml b/freetype/.github/workflows/ci.yml new file mode 100644 index 00000000..3c671e5a --- /dev/null +++ b/freetype/.github/workflows/ci.yml @@ -0,0 +1,46 @@ +name: CI +on: + - push + - pull_request +jobs: + x86_64-linux: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Setup Zig + run: | + sudo apt install xz-utils + sudo sh -c 'wget -c https://ziglang.org/builds/zig-linux-x86_64-0.10.0-dev.2017+a0a2ce92c.tar.xz -O - | tar -xJ --strip-components=1 -C /usr/local/bin' + - name: x86_64-linux -> aarch64-macos + run: zig build test -Dtarget=aarch64-macos.12...12-gnu + - name: test + run: | + zig build test + x86_64-windows: + runs-on: windows-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Install Git + run: choco install git + - name: Setup Zig + run: | + $ProgressPreference = 'SilentlyContinue' + Invoke-WebRequest -Uri "https://ziglang.org/builds/zig-windows-x86_64-0.10.0-dev.2017+a0a2ce92c.zip" -OutFile "C:\zig.zip" + cd C:\ + 7z x zig.zip + Add-Content $env:GITHUB_PATH "C:\zig-windows-x86_64-0.10.0-dev.2017+a0a2ce92c\" + - name: test + run: zig build test + x86_64-macos: + runs-on: macos-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + - name: Setup Zig + run: | + brew install xz + sudo sh -c 'wget -c https://ziglang.org/builds/zig-macos-x86_64-0.10.0-dev.2017+a0a2ce92c.tar.xz -O - | tar -xJ --strip-components=1 -C /usr/local/bin' + - name: test + run: zig build test diff --git a/freetype/build.zig b/freetype/build.zig new file mode 100644 index 00000000..68d8e019 --- /dev/null +++ b/freetype/build.zig @@ -0,0 +1,123 @@ +const std = @import("std"); + +const ft_root = thisDir() ++ "/upstream/freetype"; + +fn thisDir() []const u8 { + return std.fs.path.dirname(@src().file) orelse "."; +} + +pub fn buildFreeType(b: *std.build.Builder, mode: std.builtin.Mode, target: std.zig.CrossTarget, root_path: []const u8, custom_config_path: ?[]const u8) !*std.build.LibExeObjStep { + const main_abs = try std.fs.path.join(b.allocator, &.{ root_path, "src/base/ftbase.c" }); + const include_path = try std.fs.path.join(b.allocator, &.{ root_path, "include" }); + defer b.allocator.free(main_abs); + defer b.allocator.free(include_path); + + const lib = b.addStaticLibrary("freetype", main_abs); + lib.defineCMacro("FT2_BUILD_LIBRARY", "1"); + lib.setBuildMode(mode); + lib.setTarget(target); + lib.linkLibC(); + lib.addIncludePath(include_path); + if (custom_config_path) |path| lib.addIncludeDir(path); + + var sources = std.ArrayList([]const u8).init(b.allocator); + defer sources.deinit(); + + inline for (freetype_base_sources) |source| + try sources.append(source); + + const detected_target = (try std.zig.system.NativeTargetInfo.detect(b.allocator, target)).target; + + if (detected_target.os.tag == .windows) { + try sources.append("builds/windows/ftsystem.c"); + try sources.append("builds/windows/ftdebug.c"); + } else { + try sources.append("src/base/ftsystem.c"); + try sources.append("src/base/ftdebug.c"); + } + if (detected_target.os.tag.isBSD() or detected_target.os.tag == .linux) { + lib.defineCMacro("HAVE_UNISTD_H", "1"); + lib.defineCMacro("HAVE_FCNTL_H", "1"); + try sources.append("builds/unix/ftsystem.c"); + if (detected_target.os.tag == .macos) { + try sources.append("src/base/ftmac.c"); + } + } + + for (sources.items) |source| { + var path = try std.fs.path.join(b.allocator, &.{ root_path, source }); + defer b.allocator.free(path); + lib.addCSourceFile(path, &.{}); + } + + lib.install(); + + return lib; +} + +pub fn build(b: *std.build.Builder) !void { + const mode = b.standardReleaseOptions(); + const target = b.standardTargetOptions(.{}); + + const freetype = try buildFreeType(b, mode, target, ft_root, thisDir() ++ "/test/ft"); + + const dedicated_tests = b.addTest("src/main.zig"); + dedicated_tests.setBuildMode(mode); + dedicated_tests.setTarget(target); + dedicated_tests.linkLibrary(freetype); + dedicated_tests.addIncludePath(ft_root ++ "/include"); + + const main_tests = b.addTest("test/main.zig"); + main_tests.setBuildMode(mode); + main_tests.setTarget(target); + main_tests.addPackagePath("freetype", "src/main.zig"); + main_tests.linkLibrary(freetype); + main_tests.addIncludePath(thisDir() ++ "/test/ft"); + main_tests.addIncludePath(ft_root ++ "/include"); + + const test_step = b.step("test", "Run library tests"); + test_step.dependOn(&dedicated_tests.step); + test_step.dependOn(&main_tests.step); +} + +const freetype_base_sources = &[_][]const u8{ + "src/autofit/autofit.c", + "src/base/ftbbox.c", + "src/base/ftbdf.c", + "src/base/ftbitmap.c", + "src/base/ftcid.c", + "src/base/ftfstype.c", + "src/base/ftgasp.c", + "src/base/ftglyph.c", + "src/base/ftgxval.c", + "src/base/ftinit.c", + "src/base/ftmm.c", + "src/base/ftotval.c", + "src/base/ftpatent.c", + "src/base/ftpfr.c", + "src/base/ftstroke.c", + "src/base/ftsynth.c", + "src/base/fttype1.c", + "src/base/ftwinfnt.c", + "src/bdf/bdf.c", + "src/bzip2/ftbzip2.c", + "src/cache/ftcache.c", + "src/cff/cff.c", + "src/cid/type1cid.c", + "src/gzip/ftgzip.c", + "src/lzw/ftlzw.c", + "src/pcf/pcf.c", + "src/pfr/pfr.c", + "src/psaux/psaux.c", + "src/pshinter/pshinter.c", + "src/psnames/psnames.c", + "src/raster/raster.c", + "src/sdf/sdf.c", + "src/sfnt/sfnt.c", + "src/smooth/smooth.c", + "src/svg/svg.c", + "src/truetype/truetype.c", + "src/type1/type1.c", + "src/type42/type42.c", + "src/winfonts/winfnt.c", +}; diff --git a/freetype/examples/single_glyph.zig b/freetype/examples/single_glyph.zig new file mode 100644 index 00000000..b93aa5f9 --- /dev/null +++ b/freetype/examples/single_glyph.zig @@ -0,0 +1,58 @@ +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 { + const lib = try freetype.Library.init(); + defer lib.deinit(); + + const face = try lib.newFace("test/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); + + var i: usize = 0; + while (i < HEIGHT) : (i += 1) { + var j: usize = 0; + while (j < WIDTH) : (j += 1) { + const char: u8 = switch (figure[i][j]) { + 0 => ' ', + 1...128 => ';', + else => '#', + }; + std.debug.print("{c}", .{char}); + } + std.debug.print("\n", .{}); + } +} diff --git a/freetype/src/Bitmap.zig b/freetype/src/Bitmap.zig new file mode 100644 index 00000000..5a3e64e5 --- /dev/null +++ b/freetype/src/Bitmap.zig @@ -0,0 +1,54 @@ +const std = @import("std"); +const c = @import("c.zig"); +const Error = @import("error.zig").Error; +const convertError = @import("error.zig").convertError; + +const Bitmap = @This(); + +pub const PixelMode = enum { + none, + mono, + gray, + gray2, + gray4, + lcd, + lcd_v, + bgra, +}; + +handle: c.FT_Bitmap, + +pub fn init(handle: c.FT_Bitmap) Bitmap { + return Bitmap{ .handle = handle }; +} + +pub fn width(self: Bitmap) u32 { + return self.handle.width; +} + +pub fn pitch(self: Bitmap) i32 { + return self.handle.pitch; +} + +pub fn rows(self: Bitmap) u32 { + return self.handle.rows; +} + +pub fn pixelMode(self: Bitmap) PixelMode { + return switch (self.handle.pixel_mode) { + c.FT_PIXEL_MODE_NONE => .none, + c.FT_PIXEL_MODE_MONO => .mono, + c.FT_PIXEL_MODE_GRAY => .gray, + c.FT_PIXEL_MODE_GRAY2 => .gray2, + c.FT_PIXEL_MODE_GRAY4 => .gray4, + c.FT_PIXEL_MODE_LCD => .lcd, + c.FT_PIXEL_MODE_LCD_V => .lcd_v, + c.FT_PIXEL_MODE_BGRA => .bgra, + else => unreachable, + }; +} + +pub fn buffer(self: Bitmap) []u8 { + const buffer_size = std.math.absCast(self.pitch()) * self.rows(); + return self.handle.buffer[0..buffer_size]; +} diff --git a/freetype/src/BitmapGlyph.zig b/freetype/src/BitmapGlyph.zig new file mode 100644 index 00000000..019e7da5 --- /dev/null +++ b/freetype/src/BitmapGlyph.zig @@ -0,0 +1,35 @@ +const std = @import("std"); +const c = @import("c.zig"); +const Bitmap = @import("Bitmap.zig"); +const Error = @import("error.zig").Error; +const convertError = @import("error.zig").convertError; + +const BitmapGlyph = @This(); + +handle: c.FT_BitmapGlyph, + +pub fn init(handle: c.FT_BitmapGlyph) BitmapGlyph { + return BitmapGlyph{ .handle = handle }; +} + +pub fn deinit(self: BitmapGlyph) void { + c.FT_Done_Glyph(@ptrCast(c.FT_Glyph, self.handle)); +} + +pub fn clone(self: BitmapGlyph) Error!BitmapGlyph { + var res = std.mem.zeroes(c.FT_Glyph); + try convertError(c.FT_Glyph_Copy(@ptrCast(c.FT_Glyph, self.handle), &res)); + return BitmapGlyph.init(@ptrCast(c.FT_BitmapGlyph, res)); +} + +pub fn left(self: BitmapGlyph) i32 { + return self.handle.*.left; +} + +pub fn top(self: BitmapGlyph) i32 { + return self.handle.*.top; +} + +pub fn bitmap(self: BitmapGlyph) Bitmap { + return Bitmap.init(self.handle.*.bitmap); +} diff --git a/freetype/src/Face.zig b/freetype/src/Face.zig new file mode 100644 index 00000000..45cbe2b5 --- /dev/null +++ b/freetype/src/Face.zig @@ -0,0 +1,267 @@ +const std = @import("std"); +const c = @import("c.zig"); +const types = @import("types.zig"); +const GlyphSlot = @import("GlyphSlot.zig"); +const Library = @import("Library.zig"); +const Error = @import("error.zig").Error; +const convertError = @import("error.zig").convertError; +const utils = @import("utils.zig"); + +const Face = @This(); + +pub const SizeMetrics = c.FT_Size_Metrics; +pub const KerningMode = enum(u2) { + default = c.FT_KERNING_DEFAULT, + unfitted = c.FT_KERNING_UNFITTED, + unscaled = c.FT_KERNING_UNSCALED, +}; +pub const LoadFlags = packed struct { + no_scale: bool = false, + no_hinting: bool = false, + render: bool = false, + no_bitmap: bool = false, + vertical_layout: bool = false, + force_autohint: bool = false, + crop_bitmap: bool = false, + pedantic: bool = false, + ignore_global_advance_with: bool = false, + no_recurse: bool = false, + ignore_transform: bool = false, + monochrome: bool = false, + linear_design: bool = false, + no_autohint: bool = false, + target_normal: bool = false, + target_light: bool = false, + target_mono: bool = false, + target_lcd: bool = false, + target_lcd_v: bool = false, + color: bool = false, + + pub const Flag = enum(u21) { + no_scale = c.FT_LOAD_NO_SCALE, + no_hinting = c.FT_LOAD_NO_HINTING, + render = c.FT_LOAD_RENDER, + no_bitmap = c.FT_LOAD_NO_BITMAP, + vertical_layout = c.FT_LOAD_VERTICAL_LAYOUT, + force_autohint = c.FT_LOAD_FORCE_AUTOHINT, + crop_bitmap = c.FT_LOAD_CROP_BITMAP, + pedantic = c.FT_LOAD_PEDANTIC, + ignore_global_advance_with = c.FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH, + no_recurse = c.FT_LOAD_NO_RECURSE, + ignore_transform = c.FT_LOAD_IGNORE_TRANSFORM, + monochrome = c.FT_LOAD_MONOCHROME, + linear_design = c.FT_LOAD_LINEAR_DESIGN, + no_autohint = c.FT_LOAD_NO_AUTOHINT, + target_normal = c.FT_LOAD_TARGET_NORMAL, + target_light = c.FT_LOAD_TARGET_LIGHT, + target_mono = c.FT_LOAD_TARGET_MONO, + target_lcd = c.FT_LOAD_TARGET_LCD, + target_lcd_v = c.FT_LOAD_TARGET_LCD_V, + color = c.FT_LOAD_COLOR, + }; + + pub fn toBitFields(flags: LoadFlags) u21 { + return utils.structToBitFields(u21, Flag, flags); + } +}; +pub const StyleFlags = packed struct { + bold: bool = false, + italic: bool = false, + + pub const Flag = enum(u2) { + bold = c.FT_STYLE_FLAG_BOLD, + italic = c.FT_STYLE_FLAG_ITALIC, + }; + + pub fn toBitFields(flags: StyleFlags) u2 { + return utils.structToBitFields(u2, StyleFlags, Flag, flags); + } +}; + +handle: c.FT_Face, +glyph: GlyphSlot, + +pub fn init(handle: c.FT_Face) Face { + return Face{ + .handle = handle, + .glyph = GlyphSlot.init(handle.*.glyph), + }; +} + +pub fn deinit(self: Face) void { + convertError(c.FT_Done_Face(self.handle)) catch |err| { + std.log.err("mach/freetype: Failed to destroy Face: {}", .{err}); + }; +} + +pub fn attachFile(self: Face, path: []const u8) Error!void { + return self.attachStream(.{ + .flags = .{ .path = true }, + .data = .{ .path = path }, + }); +} + +pub fn attachMemory(self: Face, bytes: []const u8) Error!void { + return self.attachStream(.{ + .flags = .{ .memory = true }, + .data = .{ .memory = bytes }, + }); +} + +pub fn attachStream(self: Face, args: types.OpenArgs) Error!void { + return convertError(c.FT_Attach_Stream(self.handle, &args.toCInterface())); +} + +pub fn setCharSize(self: Face, pt_width: i32, pt_height: i32, horz_resolution: u16, vert_resolution: u16) Error!void { + return convertError(c.FT_Set_Char_Size(self.handle, pt_width, pt_height, horz_resolution, vert_resolution)); +} + +pub fn setPixelSizes(self: Face, pixel_width: u32, pixel_height: u32) Error!void { + return convertError(c.FT_Set_Pixel_Sizes(self.handle, pixel_width, pixel_height)); +} + +pub fn loadGlyph(self: Face, index: u32, flags: LoadFlags) Error!void { + return convertError(c.FT_Load_Glyph(self.handle, index, flags.toBitFields())); +} + +pub fn loadChar(self: Face, char: u32, flags: LoadFlags) Error!void { + return convertError(c.FT_Load_Char(self.handle, char, flags.toBitFields())); +} + +pub fn setTransform(self: Face, matrix: ?types.Matrix, delta: ?types.Vector) Error!void { + var m = matrix orelse std.mem.zeroes(types.Matrix); + var d = delta orelse std.mem.zeroes(types.Vector); + return c.FT_Set_Transform(self.handle, &m, &d); +} + +pub fn getCharIndex(self: Face, index: u32) ?u32 { + const i = c.FT_Get_Char_Index(self.handle, index); + return if (i == 0) null else i; +} + +pub fn getKerning(self: Face, left_char_index: u32, right_char_index: u32, mode: KerningMode) Error!types.Vector { + var vec = std.mem.zeroes(types.Vector); + try convertError(c.FT_Get_Kerning(self.handle, left_char_index, right_char_index, @enumToInt(mode), &vec)); + return vec; +} + +pub fn hasHorizontal(self: Face) bool { + return c.FT_HAS_HORIZONTAL(self.handle); +} + +pub fn hasVertical(self: Face) bool { + return c.FT_HAS_VERTICAL(self.handle); +} + +pub fn hasKerning(self: Face) bool { + return c.FT_HAS_KERNING(self.handle); +} + +pub fn hasFixedSizes(self: Face) bool { + return c.FT_HAS_FIXED_SIZES(self.handle); +} + +pub fn hasGlyphNames(self: Face) bool { + return c.FT_HAS_GLYPH_NAMES(self.handle); +} + +pub fn hasColor(self: Face) bool { + return c.FT_HAS_COLOR(self.handle); +} + +pub fn isScalable(self: Face) bool { + return c.FT_IS_SCALABLE(self.handle); +} + +pub fn isSfnt(self: Face) bool { + return c.FT_IS_SFNT(self.handle); +} + +pub fn isFixedWidth(self: Face) bool { + return c.FT_IS_FIXED_WIDTH(self.handle); +} + +pub fn isCidKeyed(self: Face) bool { + return c.FT_IS_CID_KEYED(self.handle); +} + +pub fn isTricky(self: Face) bool { + return c.FT_IS_TRICKY(self.handle); +} + +pub fn ascender(self: Face) i16 { + return self.handle.*.ascender; +} + +pub fn descender(self: Face) i16 { + return self.handle.*.descender; +} + +pub fn emSize(self: Face) u16 { + return self.handle.*.units_per_EM; +} + +pub fn height(self: Face) i16 { + return self.handle.*.height; +} + +pub fn maxAdvanceWidth(self: Face) i16 { + return self.handle.*.max_advance_width; +} + +pub fn maxAdvanceHeight(self: Face) i16 { + return self.handle.*.max_advance_height; +} + +pub fn underlinePosition(self: Face) i16 { + return self.handle.*.underline_position; +} + +pub fn underlineThickness(self: Face) i16 { + return self.handle.*.underline_thickness; +} + +pub fn numFaces(self: Face) i64 { + return self.handle.*.num_faces; +} + +pub fn numGlyphs(self: Face) i64 { + return self.handle.*.num_glyphs; +} + +pub fn familyName(self: Face) ?[:0]const u8 { + const family = self.handle.*.family_name; + return if (family == null) + null + else + std.mem.span(family); +} + +pub fn styleName(self: Face) ?[:0]const u8 { + const style = self.handle.*.style_name; + return if (style == null) + null + else + std.mem.span(style); +} + +pub fn styleFlags(self: Face) StyleFlags { + const flags = self.handle.*.style_flags; + return utils.bitFieldsToStruct(StyleFlags, StyleFlags.Flag, flags); +} + +pub fn sizeMetrics(self: Face) ?SizeMetrics { + const size = self.handle.*.size; + return if (size == null) + null + else + size.*.metrics; +} + +pub fn postscriptName(self: Face) ?[:0]const u8 { + const face_name = c.FT_Get_Postscript_Name(self.handle); + return if (face_name == null) + null + else + std.mem.span(face_name); +} diff --git a/freetype/src/Glyph.zig b/freetype/src/Glyph.zig new file mode 100644 index 00000000..081f333a --- /dev/null +++ b/freetype/src/Glyph.zig @@ -0,0 +1,82 @@ +const std = @import("std"); +const c = @import("c.zig"); +const BitmapGlyph = @import("BitmapGlyph.zig"); +const Stroker = @import("Stroker.zig"); +const types = @import("types.zig"); +const Error = @import("error.zig").Error; +const convertError = @import("error.zig").convertError; + +const Glyph = @This(); + +pub const BBox = c.FT_BBox; +pub const RenderMode = enum(u3) { + normal = c.FT_RENDER_MODE_NORMAL, + light = c.FT_RENDER_MODE_LIGHT, + mono = c.FT_RENDER_MODE_MONO, + lcd = c.FT_RENDER_MODE_LCD, + lcd_v = c.FT_RENDER_MODE_LCD_V, + sdf = c.FT_RENDER_MODE_SDF, +}; +pub const BBoxMode = enum(u2) { + // https://freetype.org/freetype2/docs/reference/ft2-glyph_management.html#ft_glyph_bbox_mode + // both `unscaled` and `subpixel` constants are set to 0 + unscaled_or_subpixels = c.FT_GLYPH_BBOX_UNSCALED, + gridfit = c.FT_GLYPH_BBOX_GRIDFIT, + truncate = c.FT_GLYPH_BBOX_TRUNCATE, + pixels = c.FT_GLYPH_BBOX_PIXELS, +}; + +handle: c.FT_Glyph, + +pub fn init(handle: c.FT_Glyph) Glyph { + return Glyph{ .handle = handle }; +} + +pub fn deinit(self: Glyph) void { + c.FT_Done_Glyph(self.handle); +} + +pub fn clone(self: Glyph) Error!Glyph { + var res = std.mem.zeroes(c.FT_Glyph); + try convertError(c.FT_Glyph_Copy(self.handle, &res)); + return Glyph.init(res); +} + +pub fn transform(self: Glyph, matrix: ?types.Matrix, delta: ?types.Vector) Error!void { + var m = matrix orelse std.mem.zeroes(types.Matrix); + var d = delta orelse std.mem.zeroes(types.Vector); + try convertError(c.FT_Glyph_Transform(self.handle, &m, &d)); +} + +pub fn getCBox(self: Glyph, bbox_mode: BBoxMode) BBox { + var res = std.mem.zeroes(BBox); + c.FT_Glyph_Get_CBox(self.handle, @enumToInt(bbox_mode), &res); + return res; +} + +pub fn toBitmap(self: Glyph, render_mode: RenderMode, origin: ?types.Vector) Error!BitmapGlyph { + var res = self.handle; + var o = origin orelse std.mem.zeroes(types.Vector); + try convertError(c.FT_Glyph_To_Bitmap(&res, @enumToInt(render_mode), &o, 0)); + return BitmapGlyph.init(@ptrCast(c.FT_BitmapGlyph, self.handle)); +} + +pub fn stroke(self: Glyph, stroker: Stroker) Error!Glyph { + var res = self.handle; + try convertError(c.FT_Glyph_Stroke(&res, stroker.handle, 0)); + return Glyph.init(res); +} + +pub fn strokeBorder(self: Glyph, stroker: Stroker, inside: bool) Error!Glyph { + var res = self.handle; + try convertError(c.FT_Glyph_StrokeBorder(&res, stroker.handle, if (inside) 1 else 0, 0)); + return Glyph.init(res); +} + +pub fn advanceX(self: Glyph) isize { + return self.handle.*.advance.x; +} + +pub fn advanceY(self: Glyph) isize { + return self.handle.*.advance.y; +} diff --git a/freetype/src/GlyphSlot.zig b/freetype/src/GlyphSlot.zig new file mode 100644 index 00000000..fc24bc68 --- /dev/null +++ b/freetype/src/GlyphSlot.zig @@ -0,0 +1,79 @@ +const std = @import("std"); +const c = @import("c.zig"); +const types = @import("types.zig"); +const Glyph = @import("Glyph.zig"); +const Outline = @import("Outline.zig"); +const Bitmap = @import("Bitmap.zig"); +const Error = @import("error.zig").Error; +const convertError = @import("error.zig").convertError; + +const GlyphSlot = @This(); + +pub const GlyphMetrics = c.FT_Glyph_Metrics; +pub const SubGlyphInfo = struct { + index: i32, + flags: u32, + arg1: i32, + arg2: i32, + transform: types.Matrix, +}; + +handle: c.FT_GlyphSlot, + +pub fn init(handle: c.FT_GlyphSlot) GlyphSlot { + return GlyphSlot{ .handle = handle }; +} + +pub fn render(self: GlyphSlot, render_mode: Glyph.RenderMode) Error!void { + return convertError(c.FT_Render_Glyph(self.handle, @enumToInt(render_mode))); +} + +pub fn subGlyphInfo(self: GlyphSlot, sub_index: u32) Error!SubGlyphInfo { + var info = std.mem.zeroes(SubGlyphInfo); + try convertError(c.FT_Get_SubGlyph_Info(self.handle, sub_index, &info.index, &info.flags, &info.arg1, &info.arg2, &info.transform)); + return info; +} + +pub fn glyph(self: GlyphSlot) Error!Glyph { + var out = std.mem.zeroes(c.FT_Glyph); + try convertError(c.FT_Get_Glyph(self.handle, &out)); + return Glyph.init(out); +} + +pub fn outline(self: GlyphSlot) ?Outline { + const out = self.handle.*.outline; + const format = self.handle.*.format; + + return if (format == c.FT_GLYPH_FORMAT_OUTLINE) + Outline.init(out) + else + null; +} + +pub fn bitmap(self: GlyphSlot) Bitmap { + return Bitmap.init(self.handle.*.bitmap); +} + +pub fn bitmapLeft(self: GlyphSlot) i32 { + return self.handle.*.bitmap_left; +} + +pub fn bitmapTop(self: GlyphSlot) i32 { + return self.handle.*.bitmap_top; +} + +pub fn linearHoriAdvance(self: GlyphSlot) i64 { + return self.handle.*.linearHoriAdvance; +} + +pub fn linearVertAdvance(self: GlyphSlot) i64 { + return self.handle.*.linearVertAdvance; +} + +pub fn advance(self: GlyphSlot) types.Vector { + return self.handle.*.advance; +} + +pub fn metrics(self: GlyphSlot) GlyphMetrics { + return self.handle.*.metrics; +} diff --git a/freetype/src/Library.zig b/freetype/src/Library.zig new file mode 100644 index 00000000..55f578c3 --- /dev/null +++ b/freetype/src/Library.zig @@ -0,0 +1,60 @@ +const std = @import("std"); +const c = @import("c.zig"); +const types = @import("types.zig"); +const Face = @import("Face.zig"); +const Stroker = @import("Stroker.zig"); +const Error = @import("error.zig").Error; +const convertError = @import("error.zig").convertError; + +const Library = @This(); + +pub const LcdFilter = enum(u5) { + none = c.FT_LCD_FILTER_NONE, + default = c.FT_LCD_FILTER_DEFAULT, + light = c.FT_LCD_FILTER_LIGHT, + legacy = c.FT_LCD_FILTER_LEGACY, +}; + +handle: c.FT_Library, + +pub fn init() Error!Library { + var ft = std.mem.zeroes(Library); + try convertError(c.FT_Init_FreeType(&ft.handle)); + return ft; +} + +pub fn deinit(self: Library) void { + convertError(c.FT_Done_FreeType(self.handle)) catch |err| { + std.log.err("mach/freetype: Failed to deinitialize Library: {}", .{err}); + }; +} + +pub fn newFace(self: Library, path: []const u8, face_index: i32) Error!Face { + return self.openFace(.{ + .flags = .{ .path = true }, + .data = .{ .path = path }, + }, face_index); +} + +pub fn newFaceMemory(self: Library, bytes: []const u8, face_index: i32) Error!Face { + return self.openFace(.{ + .flags = .{ .memory = true }, + .data = .{ .memory = bytes }, + }, face_index); +} + +pub fn openFace(self: Library, args: types.OpenArgs, face_index: i32) Error!Face { + var face = std.mem.zeroes(c.FT_Face); + try convertError(c.FT_Open_Face(self.handle, &args.toCInterface(), face_index, &face)); + return Face.init(face); +} + +pub fn newStroker(self: Library) Error!Stroker { + var stroker = std.mem.zeroes(c.FT_Stroker); + try convertError(c.FT_Stroker_New(self.handle, &stroker)); + return Stroker.init(stroker); +} + +pub fn setLcdFilter(self: Library, lcd_filter: LcdFilter) Error!void { + return convertError(c.FT_Library_SetLcdFilter(self.handle, @enumToInt(lcd_filter))); +} diff --git a/freetype/src/Outline.zig b/freetype/src/Outline.zig new file mode 100644 index 00000000..5f3594e2 --- /dev/null +++ b/freetype/src/Outline.zig @@ -0,0 +1,22 @@ +const c = @import("c.zig"); +const types = @import("types.zig"); + +const Outline = @This(); + +handle: c.FT_Outline, + +pub fn init(handle: c.FT_Outline) Outline { + return Outline{ .handle = handle }; +} + +pub fn points(self: Outline) []const types.Vector { + return self.handle.points[0..@intCast(u15, self.handle.n_points)]; +} + +pub fn tags(self: Outline) []const u8 { + return self.handle.tags[0..@intCast(u15, self.handle.n_points)]; +} + +pub fn contours(self: Outline) []const i16 { + return self.handle.contours[0..@intCast(u15, self.handle.n_contours)]; +} diff --git a/freetype/src/Stroker.zig b/freetype/src/Stroker.zig new file mode 100644 index 00000000..86ec7efb --- /dev/null +++ b/freetype/src/Stroker.zig @@ -0,0 +1,32 @@ +const c = @import("c.zig"); +const Error = @import("error.zig").Error; +const convertError = @import("error.zig").convertError; + +const Stroker = @This(); + +pub const StrokerLineCap = enum(u2) { + butt = c.FT_STROKER_LINECAP_BUTT, + round = c.FT_STROKER_LINECAP_ROUND, + square = c.FT_STROKER_LINECAP_SQUARE, +}; + +pub const StrokerLineJoin = enum(u2) { + round = c.FT_STROKER_LINEJOIN_ROUND, + bevel = c.FT_STROKER_LINEJOIN_BEVEL, + miterVariable = c.FT_STROKER_LINEJOIN_MITER_VARIABLE, + miterFixed = c.FT_STROKER_LINEJOIN_MITER_FIXED, +}; + +handle: c.FT_Stroker, + +pub fn init(handle: c.FT_Stroker) Stroker { + return Stroker{ .handle = handle }; +} + +pub fn set(self: Stroker, radius: i32, line_cap: StrokerLineCap, line_join: StrokerLineJoin, miter_limit: i32) void { + c.FT_Stroker_Set(self.handle, radius, @enumToInt(line_cap), @enumToInt(line_join), miter_limit); +} + +pub fn deinit(self: Stroker) void { + c.FT_Stroker_Done(self.handle); +} diff --git a/freetype/src/c.zig b/freetype/src/c.zig new file mode 100644 index 00000000..d33f78d0 --- /dev/null +++ b/freetype/src/c.zig @@ -0,0 +1,8 @@ +pub usingnamespace @cImport({ + @cInclude("freetype/freetype.h"); + @cInclude("freetype/ftlcdfil.h"); + @cInclude("freetype/ftmodapi.h"); + @cInclude("freetype/ftstroke.h"); + @cInclude("freetype/ftsystem.h"); + @cInclude("ft2build.h"); +}); diff --git a/freetype/src/error.zig b/freetype/src/error.zig new file mode 100644 index 00000000..e8beda0e --- /dev/null +++ b/freetype/src/error.zig @@ -0,0 +1,196 @@ +const c = @import("c.zig"); + +pub const Error = error{ + CannotOpenResource, + UnknownFileFormat, + InvalidFileFormat, + InvalidVersion, + LowerModuleVersion, + InvalidArgument, + UnimplementedFeature, + InvalidTable, + InvalidOffset, + ArrayTooLarge, + MissingModule, + MissingProperty, + InvalidGlyphIndex, + InvalidCharacterCode, + InvalidGlyphFormat, + CannotRenderGlyph, + InvalidOutline, + InvalidComposite, + TooManyHints, + InvalidPixelSize, + InvalidHandle, + InvalidLibraryHandle, + InvalidDriverHandle, + InvalidFaceHandle, + InvalidSizeHandle, + InvalidSlotHandle, + InvalidCharMapHandle, + InvalidCacheHandle, + InvalidStreamHandle, + TooManyDrivers, + TooManyExtensions, + OutOfMemory, + UnlistedObject, + CannotOpenStream, + InvalidStreamSeek, + InvalidStreamSkip, + InvalidStreamRead, + InvalidStreamOperation, + InvalidFrameOperation, + NestedFrameAccess, + InvalidFrameRead, + RasterUninitialized, + RasterCorrupted, + RasterOverflow, + RasterNegativeHeight, + TooManyCaches, + InvalidOpcode, + TooFewArguments, + StackOverflow, + CodeOverflow, + BadArgument, + DivideByZero, + InvalidReference, + DebugOpCode, + ENDFInExecStream, + NestedDEFS, + InvalidCodeRange, + ExecutionTooLong, + TooManyFunctionDefs, + TooManyInstructionDefs, + TableMissing, + HorizHeaderMissing, + LocationsMissing, + NameTableMissing, + CMapTableMissing, + HmtxTableMissing, + PostTableMissing, + InvalidHorizMetrics, + InvalidCharMapFormat, + InvalidPPem, + InvalidVertMetrics, + CouldNotFindContext, + InvalidPostTableFormat, + InvalidPostTable, + Syntax, + StackUnderflow, + Ignore, + NoUnicodeGlyphName, + MissingStartfontField, + MissingFontField, + MissingSizeField, + MissingFontboundingboxField, + MissingCharsField, + MissingStartcharField, + MissingEncodingField, + MissingBbxField, + BbxTooBig, + CorruptedFontHeader, + CorruptedFontGlyphs, +}; + +pub fn convertError(err: c_int) Error!void { + return switch (err) { + c.FT_Err_Ok => {}, + c.FT_Err_Cannot_Open_Resource => Error.CannotOpenResource, + c.FT_Err_Unknown_File_Format => Error.UnknownFileFormat, + c.FT_Err_Invalid_File_Format => Error.InvalidFileFormat, + c.FT_Err_Invalid_Version => Error.InvalidVersion, + c.FT_Err_Lower_Module_Version => Error.LowerModuleVersion, + c.FT_Err_Invalid_Argument => Error.InvalidArgument, + c.FT_Err_Unimplemented_Feature => Error.UnimplementedFeature, + c.FT_Err_Invalid_Table => Error.InvalidTable, + c.FT_Err_Invalid_Offset => Error.InvalidOffset, + c.FT_Err_Array_Too_Large => Error.ArrayTooLarge, + c.FT_Err_Missing_Module => Error.MissingModule, + c.FT_Err_Missing_Property => Error.MissingProperty, + c.FT_Err_Invalid_Glyph_Index => Error.InvalidGlyphIndex, + c.FT_Err_Invalid_Character_Code => Error.InvalidCharacterCode, + c.FT_Err_Invalid_Glyph_Format => Error.InvalidGlyphFormat, + c.FT_Err_Cannot_Render_Glyph => Error.CannotRenderGlyph, + c.FT_Err_Invalid_Outline => Error.InvalidOutline, + c.FT_Err_Invalid_Composite => Error.InvalidComposite, + c.FT_Err_Too_Many_Hints => Error.TooManyHints, + c.FT_Err_Invalid_Pixel_Size => Error.InvalidPixelSize, + c.FT_Err_Invalid_Handle => Error.InvalidHandle, + c.FT_Err_Invalid_Library_Handle => Error.InvalidLibraryHandle, + c.FT_Err_Invalid_Driver_Handle => Error.InvalidDriverHandle, + c.FT_Err_Invalid_Face_Handle => Error.InvalidFaceHandle, + c.FT_Err_Invalid_Size_Handle => Error.InvalidSizeHandle, + c.FT_Err_Invalid_Slot_Handle => Error.InvalidSlotHandle, + c.FT_Err_Invalid_CharMap_Handle => Error.InvalidCharMapHandle, + c.FT_Err_Invalid_Cache_Handle => Error.InvalidCacheHandle, + c.FT_Err_Invalid_Stream_Handle => Error.InvalidStreamHandle, + c.FT_Err_Too_Many_Drivers => Error.TooManyDrivers, + c.FT_Err_Too_Many_Extensions => Error.TooManyExtensions, + c.FT_Err_Out_Of_Memory => Error.OutOfMemory, + c.FT_Err_Unlisted_Object => Error.UnlistedObject, + c.FT_Err_Cannot_Open_Stream => Error.CannotOpenStream, + c.FT_Err_Invalid_Stream_Seek => Error.InvalidStreamSeek, + c.FT_Err_Invalid_Stream_Skip => Error.InvalidStreamSkip, + c.FT_Err_Invalid_Stream_Read => Error.InvalidStreamRead, + c.FT_Err_Invalid_Stream_Operation => Error.InvalidStreamOperation, + c.FT_Err_Invalid_Frame_Operation => Error.InvalidFrameOperation, + c.FT_Err_Nested_Frame_Access => Error.NestedFrameAccess, + c.FT_Err_Invalid_Frame_Read => Error.InvalidFrameRead, + c.FT_Err_Raster_Uninitialized => Error.RasterUninitialized, + c.FT_Err_Raster_Corrupted => Error.RasterCorrupted, + c.FT_Err_Raster_Overflow => Error.RasterOverflow, + c.FT_Err_Raster_Negative_Height => Error.RasterNegativeHeight, + c.FT_Err_Too_Many_Caches => Error.TooManyCaches, + c.FT_Err_Invalid_Opcode => Error.InvalidOpcode, + c.FT_Err_Too_Few_Arguments => Error.TooFewArguments, + c.FT_Err_Stack_Overflow => Error.StackOverflow, + c.FT_Err_Code_Overflow => Error.CodeOverflow, + c.FT_Err_Bad_Argument => Error.BadArgument, + c.FT_Err_Divide_By_Zero => Error.DivideByZero, + c.FT_Err_Invalid_Reference => Error.InvalidReference, + c.FT_Err_Debug_OpCode => Error.DebugOpCode, + c.FT_Err_ENDF_In_Exec_Stream => Error.ENDFInExecStream, + c.FT_Err_Nested_DEFS => Error.NestedDEFS, + c.FT_Err_Invalid_CodeRange => Error.InvalidCodeRange, + c.FT_Err_Execution_Too_Long => Error.ExecutionTooLong, + c.FT_Err_Too_Many_Function_Defs => Error.TooManyFunctionDefs, + c.FT_Err_Too_Many_Instruction_Defs => Error.TooManyInstructionDefs, + c.FT_Err_Table_Missing => Error.TableMissing, + c.FT_Err_Horiz_Header_Missing => Error.HorizHeaderMissing, + c.FT_Err_Locations_Missing => Error.LocationsMissing, + c.FT_Err_Name_Table_Missing => Error.NameTableMissing, + c.FT_Err_CMap_Table_Missing => Error.CMapTableMissing, + c.FT_Err_Hmtx_Table_Missing => Error.HmtxTableMissing, + c.FT_Err_Post_Table_Missing => Error.PostTableMissing, + c.FT_Err_Invalid_Horiz_Metrics => Error.InvalidHorizMetrics, + c.FT_Err_Invalid_CharMap_Format => Error.InvalidCharMapFormat, + c.FT_Err_Invalid_PPem => Error.InvalidPPem, + c.FT_Err_Invalid_Vert_Metrics => Error.InvalidVertMetrics, + c.FT_Err_Could_Not_Find_Context => Error.CouldNotFindContext, + c.FT_Err_Invalid_Post_Table_Format => Error.InvalidPostTableFormat, + c.FT_Err_Invalid_Post_Table => Error.InvalidPostTable, + c.FT_Err_Syntax_Error => Error.Syntax, + c.FT_Err_Stack_Underflow => Error.StackUnderflow, + c.FT_Err_Ignore => Error.Ignore, + c.FT_Err_No_Unicode_Glyph_Name => Error.NoUnicodeGlyphName, + c.FT_Err_Missing_Startfont_Field => Error.MissingStartfontField, + c.FT_Err_Missing_Font_Field => Error.MissingFontField, + c.FT_Err_Missing_Size_Field => Error.MissingSizeField, + c.FT_Err_Missing_Fontboundingbox_Field => Error.MissingFontboundingboxField, + c.FT_Err_Missing_Chars_Field => Error.MissingCharsField, + c.FT_Err_Missing_Startchar_Field => Error.MissingStartcharField, + c.FT_Err_Missing_Encoding_Field => Error.MissingEncodingField, + c.FT_Err_Missing_Bbx_Field => Error.MissingBbxField, + c.FT_Err_Bbx_Too_Big => Error.BbxTooBig, + c.FT_Err_Corrupted_Font_Header => Error.CorruptedFontHeader, + c.FT_Err_Corrupted_Font_Glyphs => Error.CorruptedFontGlyphs, + else => unreachable, + }; +} + +test "error convertion" { + const expectError = @import("std").testing.expectError; + + try convertError(c.FT_Err_Ok); + try expectError(Error.OutOfMemory, convertError(c.FT_Err_Out_Of_Memory)); +} diff --git a/freetype/src/main.zig b/freetype/src/main.zig new file mode 100644 index 00000000..3b466638 --- /dev/null +++ b/freetype/src/main.zig @@ -0,0 +1,26 @@ +pub const Library = @import("Library.zig"); +pub const Face = @import("Face.zig"); +pub const GlyphSlot = @import("GlyphSlot.zig"); +pub const Glyph = @import("Glyph.zig"); +pub const BitmapGlyph = @import("BitmapGlyph.zig"); +pub const Bitmap = @import("Bitmap.zig"); +pub const Outline = @import("Outline.zig"); +pub const Stroker = @import("Stroker.zig"); +pub const Error = @import("error.zig").Error; +pub const C = @import("c.zig"); +pub usingnamespace @import("types.zig"); + +test { + const refAllDecls = @import("std").testing.refAllDecls; + refAllDecls(@import("Library.zig")); + refAllDecls(@import("Face.zig")); + refAllDecls(@import("GlyphSlot.zig")); + refAllDecls(@import("Glyph.zig")); + refAllDecls(@import("BitmapGlyph.zig")); + refAllDecls(@import("Bitmap.zig")); + refAllDecls(@import("Outline.zig")); + refAllDecls(@import("Stroker.zig")); + refAllDecls(@import("types.zig")); + refAllDecls(@import("error.zig")); + refAllDecls(@import("utils.zig")); +} diff --git a/freetype/src/types.zig b/freetype/src/types.zig new file mode 100644 index 00000000..a5d5678a --- /dev/null +++ b/freetype/src/types.zig @@ -0,0 +1,56 @@ +const std = @import("std"); +const c = @import("c.zig"); +const utils = @import("utils.zig"); + +pub const Vector = c.FT_Vector; +pub const Matrix = c.FT_Matrix; + +pub const OpenFlags = packed struct { + memory: bool = false, + stream: bool = false, + path: bool = false, + driver: bool = false, + params: bool = false, + + pub const Flag = enum(u5) { + memory = c.FT_OPEN_MEMORY, + stream = c.FT_OPEN_STREAM, + path = c.FT_OPEN_PATHNAME, + driver = c.FT_OPEN_DRIVER, + params = c.FT_OPEN_PARAMS, + }; + + pub fn toBitFields(flags: OpenFlags) u5 { + return utils.structToBitFields(u5, Flag, flags); + } +}; + +pub const OpenArgs = struct { + flags: OpenFlags, + data: union(enum) { + memory: []const u8, + path: []const u8, + stream: c.FT_Stream, + driver: c.FT_Module, + params: []const c.FT_Parameter, + }, + + pub fn toCInterface(self: OpenArgs) c.FT_Open_Args { + var oa = std.mem.zeroes(c.FT_Open_Args); + oa.flags = self.flags.toBitFields(); + switch (self.data) { + .memory => |d| { + oa.memory_base = d.ptr; + oa.memory_size = @truncate(u31, d.len); + }, + .path => |*d| oa.pathname = @intToPtr(*u8, @ptrToInt(d.ptr)), + .stream => |d| oa.stream = d, + .driver => |d| oa.driver = d, + .params => |*d| { + oa.params = @intToPtr(*c.FT_Parameter, @ptrToInt(d.ptr)); + oa.num_params = @intCast(u31, d.len); + }, + } + return oa; + } +}; diff --git a/freetype/src/utils.zig b/freetype/src/utils.zig new file mode 100644 index 00000000..5b3dc1fe --- /dev/null +++ b/freetype/src/utils.zig @@ -0,0 +1,48 @@ +const std = @import("std"); +const meta = std.meta; +const mem = std.mem; +const testing = std.testing; + +pub fn structToBitFields(comptime IntType: type, comptime EnumDataType: type, flags: anytype) IntType { + var value: IntType = 0; + inline for (comptime meta.fieldNames(EnumDataType)) |field_name| { + if (@field(flags, field_name)) { + value |= @enumToInt(@field(EnumDataType, field_name)); + } + } + return value; +} + +pub fn bitFieldsToStruct(comptime StructType: type, comptime EnumDataType: type, flags: anytype) StructType { + var value = mem.zeroes(StructType); + inline for (comptime meta.fieldNames(EnumDataType)) |field_name| { + if (flags & (@enumToInt(@field(EnumDataType, field_name))) != 0) { + @field(value, field_name) = true; + } + } + return value; +} + +const TestEnum = enum(u16) { + filed_1 = (1 << 1), + filed_2 = (1 << 2), + filed_3 = (1 << 3), +}; + +const TestStruct = packed struct { + filed_1: bool = false, + filed_2: bool = false, + filed_3: bool = false, +}; + +test "struct fields to bit fields" { + try testing.expectEqual(@as(u16, (1 << 1) | (1 << 3)), structToBitFields(u16, TestEnum, TestStruct{ + .filed_1 = true, + .filed_3 = true, + })); + try testing.expectEqual(@as(u16, 0), structToBitFields(u16, TestEnum, TestStruct{})); +} + +test "bit fields to struct" { + try testing.expectEqual(TestStruct{ .filed_1 = true, .filed_2 = true, .filed_3 = false }, bitFieldsToStruct(TestStruct, TestEnum, (1 << 1) | (1 << 2))); +} diff --git a/freetype/test/ft/ft2build.h b/freetype/test/ft/ft2build.h new file mode 100644 index 00000000..a590880f --- /dev/null +++ b/freetype/test/ft/ft2build.h @@ -0,0 +1,9 @@ +#ifndef FT2_BUILD_MACH_H_ +#define FT2_BUILD_MACH_H_ + +#define FT_CONFIG_OPTIONS_H +#define FT_CONFIG_MODULES_H + +#include + +#endif \ No newline at end of file diff --git a/freetype/test/ft/mach_ftmodule.h b/freetype/test/ft/mach_ftmodule.h new file mode 100644 index 00000000..c741a419 --- /dev/null +++ b/freetype/test/ft/mach_ftmodule.h @@ -0,0 +1,33 @@ +/* + * This file registers the FreeType modules compiled into the library. + * + * If you use GNU make, this file IS NOT USED! Instead, it is created in + * the objects directory (normally `/objs/`) based on information + * from `/modules.cfg`. + * + * Please read `docs/INSTALL.ANY` and `docs/CUSTOMIZE` how to compile + * FreeType without GNU make. + * + */ + +FT_USE_MODULE(FT_Module_Class, autofit_module_class) +FT_USE_MODULE(FT_Driver_ClassRec, tt_driver_class) +FT_USE_MODULE(FT_Driver_ClassRec, t1_driver_class) +FT_USE_MODULE(FT_Driver_ClassRec, cff_driver_class) +FT_USE_MODULE(FT_Driver_ClassRec, t1cid_driver_class) +FT_USE_MODULE(FT_Driver_ClassRec, pfr_driver_class) +FT_USE_MODULE(FT_Driver_ClassRec, t42_driver_class) +FT_USE_MODULE(FT_Driver_ClassRec, winfnt_driver_class) +FT_USE_MODULE(FT_Driver_ClassRec, pcf_driver_class) +FT_USE_MODULE(FT_Driver_ClassRec, bdf_driver_class) +FT_USE_MODULE(FT_Module_Class, psaux_module_class) +FT_USE_MODULE(FT_Module_Class, psnames_module_class) +FT_USE_MODULE(FT_Module_Class, pshinter_module_class) +FT_USE_MODULE(FT_Module_Class, sfnt_module_class) +FT_USE_MODULE(FT_Renderer_Class, ft_smooth_renderer_class) +FT_USE_MODULE(FT_Renderer_Class, ft_raster1_renderer_class) +FT_USE_MODULE(FT_Renderer_Class, ft_sdf_renderer_class) +FT_USE_MODULE(FT_Renderer_Class, ft_bitmap_sdf_renderer_class) +FT_USE_MODULE(FT_Renderer_Class, ft_svg_renderer_class) + +/* EOF */ diff --git a/freetype/test/ft/mach_ftoption.h b/freetype/test/ft/mach_ftoption.h new file mode 100644 index 00000000..093ab59e --- /dev/null +++ b/freetype/test/ft/mach_ftoption.h @@ -0,0 +1,964 @@ +/**************************************************************************** + * + * ftoption.h + * + * User-selectable configuration macros (specification only). + * + * Copyright (C) 1996-2022 by + * David Turner, Robert Wilhelm, and Werner Lemberg. + * + * This file is part of the FreeType project, and may only be used, + * modified, and distributed under the terms of the FreeType project + * license, LICENSE.TXT. By continuing to use, modify, or distribute + * this file you indicate that you have read the license and + * understand and accept it fully. + * + */ + +#ifndef FTOPTION_H_ +#define FTOPTION_H_ + +#include + +FT_BEGIN_HEADER + +/************************************************************************** + * + * USER-SELECTABLE CONFIGURATION MACROS + * + * This file contains the default configuration macro definitions for a + * standard build of the FreeType library. There are three ways to use + * this file to build project-specific versions of the library: + * + * - You can modify this file by hand, but this is not recommended in + * cases where you would like to build several versions of the library + * from a single source directory. + * + * - You can put a copy of this file in your build directory, more + * precisely in `$BUILD/freetype/config/ftoption.h`, where `$BUILD` is + * the name of a directory that is included _before_ the FreeType include + * path during compilation. + * + * The default FreeType Makefiles use the build directory + * `builds/` by default, but you can easily change that for your + * own projects. + * + * - Copy the file to `$BUILD/ft2build.h` and modify it + * slightly to pre-define the macro `FT_CONFIG_OPTIONS_H` used to locate + * this file during the build. For example, + * + * ``` + * #define FT_CONFIG_OPTIONS_H + * #include + * ``` + * + * will use `$BUILD/myftoptions.h` instead of this file for macro + * definitions. + * + * Note also that you can similarly pre-define the macro + * `FT_CONFIG_MODULES_H` used to locate the file listing of the modules + * that are statically linked to the library at compile time. By + * default, this file is ``. + * + * We highly recommend using the third method whenever possible. + * + */ + +/*************************************************************************/ +/*************************************************************************/ +/**** ****/ +/**** G E N E R A L F R E E T Y P E 2 C O N F I G U R A T I O N ****/ +/**** ****/ +/*************************************************************************/ +/*************************************************************************/ + +/*#************************************************************************ + * + * If you enable this configuration option, FreeType recognizes an + * environment variable called `FREETYPE_PROPERTIES`, which can be used to + * control the various font drivers and modules. The controllable + * properties are listed in the section @properties. + * + * You have to undefine this configuration option on platforms that lack + * the concept of environment variables (and thus don't have the `getenv` + * function), for example Windows CE. + * + * `FREETYPE_PROPERTIES` has the following syntax form (broken here into + * multiple lines for better readability). + * + * ``` + * + * ':' + * '=' + * + * ':' + * '=' + * ... + * ``` + * + * Example: + * + * ``` + * FREETYPE_PROPERTIES=truetype:interpreter-version=35 \ + * cff:no-stem-darkening=1 + * ``` + * + */ +#define FT_CONFIG_OPTION_ENVIRONMENT_PROPERTIES + +/************************************************************************** + * + * Uncomment the line below if you want to activate LCD rendering + * technology similar to ClearType in this build of the library. This + * technology triples the resolution in the direction color subpixels. To + * mitigate color fringes inherent to this technology, you also need to + * explicitly set up LCD filtering. + * + * When this macro is not defined, FreeType offers alternative LCD + * rendering technology that produces excellent output. + */ +/* #define FT_CONFIG_OPTION_SUBPIXEL_RENDERING */ + +/************************************************************************** + * + * Many compilers provide a non-ANSI 64-bit data type that can be used by + * FreeType to speed up some computations. However, this will create some + * problems when compiling the library in strict ANSI mode. + * + * For this reason, the use of 64-bit integers is normally disabled when + * the `__STDC__` macro is defined. You can however disable this by + * defining the macro `FT_CONFIG_OPTION_FORCE_INT64` here. + * + * For most compilers, this will only create compilation warnings when + * building the library. + * + * ObNote: The compiler-specific 64-bit integers are detected in the + * file `ftconfig.h` either statically or through the `configure` + * script on supported platforms. + */ +#undef FT_CONFIG_OPTION_FORCE_INT64 + +/************************************************************************** + * + * If this macro is defined, do not try to use an assembler version of + * performance-critical functions (e.g., @FT_MulFix). You should only do + * that to verify that the assembler function works properly, or to execute + * benchmark tests of the various implementations. + */ +/* #define FT_CONFIG_OPTION_NO_ASSEMBLER */ + +/************************************************************************** + * + * If this macro is defined, try to use an inlined assembler version of the + * @FT_MulFix function, which is a 'hotspot' when loading and hinting + * glyphs, and which should be executed as fast as possible. + * + * Note that if your compiler or CPU is not supported, this will default to + * the standard and portable implementation found in `ftcalc.c`. + */ +#define FT_CONFIG_OPTION_INLINE_MULFIX + +/************************************************************************** + * + * LZW-compressed file support. + * + * FreeType now handles font files that have been compressed with the + * `compress` program. This is mostly used to parse many of the PCF + * files that come with various X11 distributions. The implementation + * uses NetBSD's `zopen` to partially uncompress the file on the fly (see + * `src/lzw/ftgzip.c`). + * + * Define this macro if you want to enable this 'feature'. + */ +#define FT_CONFIG_OPTION_USE_LZW + +/************************************************************************** + * + * Gzip-compressed file support. + * + * FreeType now handles font files that have been compressed with the + * `gzip` program. This is mostly used to parse many of the PCF files + * that come with XFree86. The implementation uses 'zlib' to partially + * uncompress the file on the fly (see `src/gzip/ftgzip.c`). + * + * Define this macro if you want to enable this 'feature'. See also the + * macro `FT_CONFIG_OPTION_SYSTEM_ZLIB` below. + */ +#define FT_CONFIG_OPTION_USE_ZLIB + +/************************************************************************** + * + * ZLib library selection + * + * This macro is only used when `FT_CONFIG_OPTION_USE_ZLIB` is defined. + * It allows FreeType's 'ftgzip' component to link to the system's + * installation of the ZLib library. This is useful on systems like + * Unix or VMS where it generally is already available. + * + * If you let it undefined, the component will use its own copy of the + * zlib sources instead. These have been modified to be included + * directly within the component and **not** export external function + * names. This allows you to link any program with FreeType _and_ ZLib + * without linking conflicts. + * + * Do not `#undef` this macro here since the build system might define + * it for certain configurations only. + * + * If you use a build system like cmake or the `configure` script, + * options set by those programs have precedence, overwriting the value + * here with the configured one. + * + * If you use the GNU make build system directly (that is, without the + * `configure` script) and you define this macro, you also have to pass + * `SYSTEM_ZLIB=yes` as an argument to make. + */ +/* #define FT_CONFIG_OPTION_SYSTEM_ZLIB */ + +/************************************************************************** + * + * Bzip2-compressed file support. + * + * FreeType now handles font files that have been compressed with the + * `bzip2` program. This is mostly used to parse many of the PCF files + * that come with XFree86. The implementation uses `libbz2` to partially + * uncompress the file on the fly (see `src/bzip2/ftbzip2.c`). Contrary + * to gzip, bzip2 currently is not included and need to use the system + * available bzip2 implementation. + * + * Define this macro if you want to enable this 'feature'. + * + * If you use a build system like cmake or the `configure` script, + * options set by those programs have precedence, overwriting the value + * here with the configured one. + */ +/* #define FT_CONFIG_OPTION_USE_BZIP2 */ + +/************************************************************************** + * + * Define to disable the use of file stream functions and types, `FILE`, + * `fopen`, etc. Enables the use of smaller system libraries on embedded + * systems that have multiple system libraries, some with or without file + * stream support, in the cases where file stream support is not necessary + * such as memory loading of font files. + */ +/* #define FT_CONFIG_OPTION_DISABLE_STREAM_SUPPORT */ + +/************************************************************************** + * + * PNG bitmap support. + * + * FreeType now handles loading color bitmap glyphs in the PNG format. + * This requires help from the external libpng library. Uncompressed + * color bitmaps do not need any external libraries and will be supported + * regardless of this configuration. + * + * Define this macro if you want to enable this 'feature'. + * + * If you use a build system like cmake or the `configure` script, + * options set by those programs have precedence, overwriting the value + * here with the configured one. + */ +/* #define FT_CONFIG_OPTION_USE_PNG */ + +/************************************************************************** + * + * HarfBuzz support. + * + * FreeType uses the HarfBuzz library to improve auto-hinting of OpenType + * fonts. If available, many glyphs not directly addressable by a font's + * character map will be hinted also. + * + * Define this macro if you want to enable this 'feature'. + * + * If you use a build system like cmake or the `configure` script, + * options set by those programs have precedence, overwriting the value + * here with the configured one. + */ +/* #define FT_CONFIG_OPTION_USE_HARFBUZZ */ + +/************************************************************************** + * + * Brotli support. + * + * FreeType uses the Brotli library to provide support for decompressing + * WOFF2 streams. + * + * Define this macro if you want to enable this 'feature'. + * + * If you use a build system like cmake or the `configure` script, + * options set by those programs have precedence, overwriting the value + * here with the configured one. + */ +/* #define FT_CONFIG_OPTION_USE_BROTLI */ + +/************************************************************************** + * + * Glyph Postscript Names handling + * + * By default, FreeType 2 is compiled with the 'psnames' module. This + * module is in charge of converting a glyph name string into a Unicode + * value, or return a Macintosh standard glyph name for the use with the + * TrueType 'post' table. + * + * Undefine this macro if you do not want 'psnames' compiled in your + * build of FreeType. This has the following effects: + * + * - The TrueType driver will provide its own set of glyph names, if you + * build it to support postscript names in the TrueType 'post' table, + * but will not synthesize a missing Unicode charmap. + * + * - The Type~1 driver will not be able to synthesize a Unicode charmap + * out of the glyphs found in the fonts. + * + * You would normally undefine this configuration macro when building a + * version of FreeType that doesn't contain a Type~1 or CFF driver. + */ +#define FT_CONFIG_OPTION_POSTSCRIPT_NAMES + +/************************************************************************** + * + * Postscript Names to Unicode Values support + * + * By default, FreeType~2 is built with the 'psnames' module compiled in. + * Among other things, the module is used to convert a glyph name into a + * Unicode value. This is especially useful in order to synthesize on + * the fly a Unicode charmap from the CFF/Type~1 driver through a big + * table named the 'Adobe Glyph List' (AGL). + * + * Undefine this macro if you do not want the Adobe Glyph List compiled + * in your 'psnames' module. The Type~1 driver will not be able to + * synthesize a Unicode charmap out of the glyphs found in the fonts. + */ +#define FT_CONFIG_OPTION_ADOBE_GLYPH_LIST + +/************************************************************************** + * + * Support for Mac fonts + * + * Define this macro if you want support for outline fonts in Mac format + * (mac dfont, mac resource, macbinary containing a mac resource) on + * non-Mac platforms. + * + * Note that the 'FOND' resource isn't checked. + */ +#define FT_CONFIG_OPTION_MAC_FONTS + +/************************************************************************** + * + * Guessing methods to access embedded resource forks + * + * Enable extra Mac fonts support on non-Mac platforms (e.g., GNU/Linux). + * + * Resource forks which include fonts data are stored sometimes in + * locations which users or developers don't expected. In some cases, + * resource forks start with some offset from the head of a file. In + * other cases, the actual resource fork is stored in file different from + * what the user specifies. If this option is activated, FreeType tries + * to guess whether such offsets or different file names must be used. + * + * Note that normal, direct access of resource forks is controlled via + * the `FT_CONFIG_OPTION_MAC_FONTS` option. + */ +#ifdef FT_CONFIG_OPTION_MAC_FONTS +#define FT_CONFIG_OPTION_GUESSING_EMBEDDED_RFORK +#endif + +/************************************************************************** + * + * Allow the use of `FT_Incremental_Interface` to load typefaces that + * contain no glyph data, but supply it via a callback function. This is + * required by clients supporting document formats which supply font data + * incrementally as the document is parsed, such as the Ghostscript + * interpreter for the PostScript language. + */ +#define FT_CONFIG_OPTION_INCREMENTAL + +/************************************************************************** + * + * The size in bytes of the render pool used by the scan-line converter to + * do all of its work. + */ +#define FT_RENDER_POOL_SIZE 16384L + +/************************************************************************** + * + * FT_MAX_MODULES + * + * The maximum number of modules that can be registered in a single + * FreeType library object. 32~is the default. + */ +#define FT_MAX_MODULES 32 + +/************************************************************************** + * + * Debug level + * + * FreeType can be compiled in debug or trace mode. In debug mode, + * errors are reported through the 'ftdebug' component. In trace mode, + * additional messages are sent to the standard output during execution. + * + * Define `FT_DEBUG_LEVEL_ERROR` to build the library in debug mode. + * Define `FT_DEBUG_LEVEL_TRACE` to build it in trace mode. + * + * Don't define any of these macros to compile in 'release' mode! + * + * Do not `#undef` these macros here since the build system might define + * them for certain configurations only. + */ +/* #define FT_DEBUG_LEVEL_ERROR */ +/* #define FT_DEBUG_LEVEL_TRACE */ + +/************************************************************************** + * + * Logging + * + * Compiling FreeType in debug or trace mode makes FreeType write error + * and trace log messages to `stderr`. Enabling this macro + * automatically forces the `FT_DEBUG_LEVEL_ERROR` and + * `FT_DEBUG_LEVEL_TRACE` macros and allows FreeType to write error and + * trace log messages to a file instead of `stderr`. For writing logs + * to a file, FreeType uses an the external `dlg` library (the source + * code is in `src/dlg`). + * + * This option needs a C99 compiler. + */ +/* #define FT_DEBUG_LOGGING */ + +/************************************************************************** + * + * Autofitter debugging + * + * If `FT_DEBUG_AUTOFIT` is defined, FreeType provides some means to + * control the autofitter behaviour for debugging purposes with global + * boolean variables (consequently, you should **never** enable this + * while compiling in 'release' mode): + * + * ``` + * _af_debug_disable_horz_hints + * _af_debug_disable_vert_hints + * _af_debug_disable_blue_hints + * ``` + * + * Additionally, the following functions provide dumps of various + * internal autofit structures to stdout (using `printf`): + * + * ``` + * af_glyph_hints_dump_points + * af_glyph_hints_dump_segments + * af_glyph_hints_dump_edges + * af_glyph_hints_get_num_segments + * af_glyph_hints_get_segment_offset + * ``` + * + * As an argument, they use another global variable: + * + * ``` + * _af_debug_hints + * ``` + * + * Please have a look at the `ftgrid` demo program to see how those + * variables and macros should be used. + * + * Do not `#undef` these macros here since the build system might define + * them for certain configurations only. + */ +/* #define FT_DEBUG_AUTOFIT */ + +/************************************************************************** + * + * Memory Debugging + * + * FreeType now comes with an integrated memory debugger that is capable + * of detecting simple errors like memory leaks or double deletes. To + * compile it within your build of the library, you should define + * `FT_DEBUG_MEMORY` here. + * + * Note that the memory debugger is only activated at runtime when when + * the _environment_ variable `FT2_DEBUG_MEMORY` is defined also! + * + * Do not `#undef` this macro here since the build system might define it + * for certain configurations only. + */ +/* #define FT_DEBUG_MEMORY */ + +/************************************************************************** + * + * Module errors + * + * If this macro is set (which is _not_ the default), the higher byte of + * an error code gives the module in which the error has occurred, while + * the lower byte is the real error code. + * + * Setting this macro makes sense for debugging purposes only, since it + * would break source compatibility of certain programs that use + * FreeType~2. + * + * More details can be found in the files `ftmoderr.h` and `fterrors.h`. + */ +#undef FT_CONFIG_OPTION_USE_MODULE_ERRORS + +/************************************************************************** + * + * OpenType SVG Glyph Support + * + * Setting this macro enables support for OpenType SVG glyphs. By + * default, FreeType can only fetch SVG documents. However, it can also + * render them if external rendering hook functions are plugged in at + * runtime. + * + * More details on the hooks can be found in file `otsvg.h`. + */ +#define FT_CONFIG_OPTION_SVG + +/************************************************************************** + * + * Error Strings + * + * If this macro is set, `FT_Error_String` will return meaningful + * descriptions. This is not enabled by default to reduce the overall + * size of FreeType. + * + * More details can be found in the file `fterrors.h`. + */ +/* #define FT_CONFIG_OPTION_ERROR_STRINGS */ + +/*************************************************************************/ +/*************************************************************************/ +/**** ****/ +/**** S F N T D R I V E R C O N F I G U R A T I O N ****/ +/**** ****/ +/*************************************************************************/ +/*************************************************************************/ + +/************************************************************************** + * + * Define `TT_CONFIG_OPTION_EMBEDDED_BITMAPS` if you want to support + * embedded bitmaps in all formats using the 'sfnt' module (namely + * TrueType~& OpenType). + */ +#define TT_CONFIG_OPTION_EMBEDDED_BITMAPS + +/************************************************************************** + * + * Define `TT_CONFIG_OPTION_COLOR_LAYERS` if you want to support colored + * outlines (from the 'COLR'/'CPAL' tables) in all formats using the 'sfnt' + * module (namely TrueType~& OpenType). + */ +#define TT_CONFIG_OPTION_COLOR_LAYERS + +/************************************************************************** + * + * Define `TT_CONFIG_OPTION_POSTSCRIPT_NAMES` if you want to be able to + * load and enumerate the glyph Postscript names in a TrueType or OpenType + * file. + * + * Note that when you do not compile the 'psnames' module by undefining the + * above `FT_CONFIG_OPTION_POSTSCRIPT_NAMES`, the 'sfnt' module will + * contain additional code used to read the PS Names table from a font. + * + * (By default, the module uses 'psnames' to extract glyph names.) + */ +#define TT_CONFIG_OPTION_POSTSCRIPT_NAMES + +/************************************************************************** + * + * Define `TT_CONFIG_OPTION_SFNT_NAMES` if your applications need to access + * the internal name table in a SFNT-based format like TrueType or + * OpenType. The name table contains various strings used to describe the + * font, like family name, copyright, version, etc. It does not contain + * any glyph name though. + * + * Accessing SFNT names is done through the functions declared in + * `ftsnames.h`. + */ +#define TT_CONFIG_OPTION_SFNT_NAMES + +/************************************************************************** + * + * TrueType CMap support + * + * Here you can fine-tune which TrueType CMap table format shall be + * supported. + */ +#define TT_CONFIG_CMAP_FORMAT_0 +#define TT_CONFIG_CMAP_FORMAT_2 +#define TT_CONFIG_CMAP_FORMAT_4 +#define TT_CONFIG_CMAP_FORMAT_6 +#define TT_CONFIG_CMAP_FORMAT_8 +#define TT_CONFIG_CMAP_FORMAT_10 +#define TT_CONFIG_CMAP_FORMAT_12 +#define TT_CONFIG_CMAP_FORMAT_13 +#define TT_CONFIG_CMAP_FORMAT_14 + +/*************************************************************************/ +/*************************************************************************/ +/**** ****/ +/**** T R U E T Y P E D R I V E R C O N F I G U R A T I O N ****/ +/**** ****/ +/*************************************************************************/ +/*************************************************************************/ + +/************************************************************************** + * + * Define `TT_CONFIG_OPTION_BYTECODE_INTERPRETER` if you want to compile a + * bytecode interpreter in the TrueType driver. + * + * By undefining this, you will only compile the code necessary to load + * TrueType glyphs without hinting. + * + * Do not `#undef` this macro here, since the build system might define it + * for certain configurations only. + */ +#define TT_CONFIG_OPTION_BYTECODE_INTERPRETER + +/************************************************************************** + * + * Define `TT_CONFIG_OPTION_SUBPIXEL_HINTING` if you want to compile + * subpixel hinting support into the TrueType driver. This modifies the + * TrueType hinting mechanism when anything but `FT_RENDER_MODE_MONO` is + * requested. + * + * In particular, it modifies the bytecode interpreter to interpret (or + * not) instructions in a certain way so that all TrueType fonts look like + * they do in a Windows ClearType (DirectWrite) environment. See [1] for a + * technical overview on what this means. See `ttinterp.h` for more + * details on the LEAN option. + * + * There are three possible values. + * + * Value 1: + * This value is associated with the 'Infinality' moniker, contributed by + * an individual nicknamed Infinality with the goal of making TrueType + * fonts render better than on Windows. A high amount of configurability + * and flexibility, down to rules for single glyphs in fonts, but also + * very slow. Its experimental and slow nature and the original + * developer losing interest meant that this option was never enabled in + * default builds. + * + * The corresponding interpreter version is v38. + * + * Value 2: + * The new default mode for the TrueType driver. The Infinality code + * base was stripped to the bare minimum and all configurability removed + * in the name of speed and simplicity. The configurability was mainly + * aimed at legacy fonts like 'Arial', 'Times New Roman', or 'Courier'. + * Legacy fonts are fonts that modify vertical stems to achieve clean + * black-and-white bitmaps. The new mode focuses on applying a minimal + * set of rules to all fonts indiscriminately so that modern and web + * fonts render well while legacy fonts render okay. + * + * The corresponding interpreter version is v40. + * + * Value 3: + * Compile both, making both v38 and v40 available (the latter is the + * default). + * + * By undefining these, you get rendering behavior like on Windows without + * ClearType, i.e., Windows XP without ClearType enabled and Win9x + * (interpreter version v35). Or not, depending on how much hinting blood + * and testing tears the font designer put into a given font. If you + * define one or both subpixel hinting options, you can switch between + * between v35 and the ones you define (using `FT_Property_Set`). + * + * This option requires `TT_CONFIG_OPTION_BYTECODE_INTERPRETER` to be + * defined. + * + * [1] + * https://www.microsoft.com/typography/cleartype/truetypecleartype.aspx + */ +/* #define TT_CONFIG_OPTION_SUBPIXEL_HINTING 1 */ +#define TT_CONFIG_OPTION_SUBPIXEL_HINTING 2 +/* #define TT_CONFIG_OPTION_SUBPIXEL_HINTING ( 1 | 2 ) */ + +/************************************************************************** + * + * Define `TT_CONFIG_OPTION_COMPONENT_OFFSET_SCALED` to compile the + * TrueType glyph loader to use Apple's definition of how to handle + * component offsets in composite glyphs. + * + * Apple and MS disagree on the default behavior of component offsets in + * composites. Apple says that they should be scaled by the scaling + * factors in the transformation matrix (roughly, it's more complex) while + * MS says they should not. OpenType defines two bits in the composite + * flags array which can be used to disambiguate, but old fonts will not + * have them. + * + * https://www.microsoft.com/typography/otspec/glyf.htm + * https://developer.apple.com/fonts/TrueType-Reference-Manual/RM06/Chap6glyf.html + */ +#undef TT_CONFIG_OPTION_COMPONENT_OFFSET_SCALED + +/************************************************************************** + * + * Define `TT_CONFIG_OPTION_GX_VAR_SUPPORT` if you want to include support + * for Apple's distortable font technology ('fvar', 'gvar', 'cvar', and + * 'avar' tables). Tagged 'Font Variations', this is now part of OpenType + * also. This has many similarities to Type~1 Multiple Masters support. + */ +#define TT_CONFIG_OPTION_GX_VAR_SUPPORT + +/************************************************************************** + * + * Define `TT_CONFIG_OPTION_BDF` if you want to include support for an + * embedded 'BDF~' table within SFNT-based bitmap formats. + */ +#define TT_CONFIG_OPTION_BDF + +/************************************************************************** + * + * Option `TT_CONFIG_OPTION_MAX_RUNNABLE_OPCODES` controls the maximum + * number of bytecode instructions executed for a single run of the + * bytecode interpreter, needed to prevent infinite loops. You don't want + * to change this except for very special situations (e.g., making a + * library fuzzer spend less time to handle broken fonts). + * + * It is not expected that this value is ever modified by a configuring + * script; instead, it gets surrounded with `#ifndef ... #endif` so that + * the value can be set as a preprocessor option on the compiler's command + * line. + */ +#ifndef TT_CONFIG_OPTION_MAX_RUNNABLE_OPCODES +#define TT_CONFIG_OPTION_MAX_RUNNABLE_OPCODES 1000000L +#endif + +/*************************************************************************/ +/*************************************************************************/ +/**** ****/ +/**** T Y P E 1 D R I V E R C O N F I G U R A T I O N ****/ +/**** ****/ +/*************************************************************************/ +/*************************************************************************/ + +/************************************************************************** + * + * `T1_MAX_DICT_DEPTH` is the maximum depth of nest dictionaries and arrays + * in the Type~1 stream (see `t1load.c`). A minimum of~4 is required. + */ +#define T1_MAX_DICT_DEPTH 5 + +/************************************************************************** + * + * `T1_MAX_SUBRS_CALLS` details the maximum number of nested sub-routine + * calls during glyph loading. + */ +#define T1_MAX_SUBRS_CALLS 16 + +/************************************************************************** + * + * `T1_MAX_CHARSTRING_OPERANDS` is the charstring stack's capacity. A + * minimum of~16 is required. + * + * The Chinese font 'MingTiEG-Medium' (covering the CNS 11643 character + * set) needs 256. + */ +#define T1_MAX_CHARSTRINGS_OPERANDS 256 + +/************************************************************************** + * + * Define this configuration macro if you want to prevent the compilation + * of the 't1afm' module, which is in charge of reading Type~1 AFM files + * into an existing face. Note that if set, the Type~1 driver will be + * unable to produce kerning distances. + */ +#undef T1_CONFIG_OPTION_NO_AFM + +/************************************************************************** + * + * Define this configuration macro if you want to prevent the compilation + * of the Multiple Masters font support in the Type~1 driver. + */ +#undef T1_CONFIG_OPTION_NO_MM_SUPPORT + +/************************************************************************** + * + * `T1_CONFIG_OPTION_OLD_ENGINE` controls whether the pre-Adobe Type~1 + * engine gets compiled into FreeType. If defined, it is possible to + * switch between the two engines using the `hinting-engine` property of + * the 'type1' driver module. + */ +/* #define T1_CONFIG_OPTION_OLD_ENGINE */ + +/*************************************************************************/ +/*************************************************************************/ +/**** ****/ +/**** C F F D R I V E R C O N F I G U R A T I O N ****/ +/**** ****/ +/*************************************************************************/ +/*************************************************************************/ + +/************************************************************************** + * + * Using `CFF_CONFIG_OPTION_DARKENING_PARAMETER_{X,Y}{1,2,3,4}` it is + * possible to set up the default values of the four control points that + * define the stem darkening behaviour of the (new) CFF engine. For more + * details please read the documentation of the `darkening-parameters` + * property (file `ftdriver.h`), which allows the control at run-time. + * + * Do **not** undefine these macros! + */ +#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_X1 500 +#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y1 400 + +#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_X2 1000 +#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y2 275 + +#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_X3 1667 +#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y3 275 + +#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_X4 2333 +#define CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y4 0 + +/************************************************************************** + * + * `CFF_CONFIG_OPTION_OLD_ENGINE` controls whether the pre-Adobe CFF engine + * gets compiled into FreeType. If defined, it is possible to switch + * between the two engines using the `hinting-engine` property of the 'cff' + * driver module. + */ +/* #define CFF_CONFIG_OPTION_OLD_ENGINE */ + +/*************************************************************************/ +/*************************************************************************/ +/**** ****/ +/**** P C F D R I V E R C O N F I G U R A T I O N ****/ +/**** ****/ +/*************************************************************************/ +/*************************************************************************/ + +/************************************************************************** + * + * There are many PCF fonts just called 'Fixed' which look completely + * different, and which have nothing to do with each other. When selecting + * 'Fixed' in KDE or Gnome one gets results that appear rather random, the + * style changes often if one changes the size and one cannot select some + * fonts at all. This option makes the 'pcf' module prepend the foundry + * name (plus a space) to the family name. + * + * We also check whether we have 'wide' characters; all put together, we + * get family names like 'Sony Fixed' or 'Misc Fixed Wide'. + * + * If this option is activated, it can be controlled with the + * `no-long-family-names` property of the 'pcf' driver module. + */ +/* #define PCF_CONFIG_OPTION_LONG_FAMILY_NAMES */ + +/*************************************************************************/ +/*************************************************************************/ +/**** ****/ +/**** A U T O F I T M O D U L E C O N F I G U R A T I O N ****/ +/**** ****/ +/*************************************************************************/ +/*************************************************************************/ + +/************************************************************************** + * + * Compile 'autofit' module with CJK (Chinese, Japanese, Korean) script + * support. + */ +#define AF_CONFIG_OPTION_CJK + +/************************************************************************** + * + * Compile 'autofit' module with fallback Indic script support, covering + * some scripts that the 'latin' submodule of the 'autofit' module doesn't + * (yet) handle. Currently, this needs option `AF_CONFIG_OPTION_CJK`. + */ +#ifdef AF_CONFIG_OPTION_CJK +#define AF_CONFIG_OPTION_INDIC +#endif + +/************************************************************************** + * + * Use TrueType-like size metrics for 'light' auto-hinting. + * + * It is strongly recommended to avoid this option, which exists only to + * help some legacy applications retain its appearance and behaviour with + * respect to auto-hinted TrueType fonts. + * + * The very reason this option exists at all are GNU/Linux distributions + * like Fedora that did not un-patch the following change (which was + * present in FreeType between versions 2.4.6 and 2.7.1, inclusive). + * + * ``` + * 2011-07-16 Steven Chu + * + * [truetype] Fix metrics on size request for scalable fonts. + * ``` + * + * This problematic commit is now reverted (more or less). + */ +/* #define AF_CONFIG_OPTION_TT_SIZE_METRICS */ + +/* */ + +/* + * This macro is obsolete. Support has been removed in FreeType version + * 2.5. + */ +/* #define FT_CONFIG_OPTION_OLD_INTERNALS */ + +/* + * The next three macros are defined if native TrueType hinting is + * requested by the definitions above. Don't change this. + */ +#ifdef TT_CONFIG_OPTION_BYTECODE_INTERPRETER +#define TT_USE_BYTECODE_INTERPRETER + +#ifdef TT_CONFIG_OPTION_SUBPIXEL_HINTING +#if TT_CONFIG_OPTION_SUBPIXEL_HINTING & 1 +#define TT_SUPPORT_SUBPIXEL_HINTING_INFINALITY +#endif + +#if TT_CONFIG_OPTION_SUBPIXEL_HINTING & 2 +#define TT_SUPPORT_SUBPIXEL_HINTING_MINIMAL +#endif +#endif +#endif + +/* + * The TT_SUPPORT_COLRV1 macro is defined to indicate to clients that this + * version of FreeType has support for 'COLR' v1 API. This definition is + * useful to FreeType clients that want to build in support for 'COLR' v1 + * depending on a tip-of-tree checkout before it is officially released in + * FreeType, and while the feature cannot yet be tested against using + * version macros. Don't change this macro. This may be removed once the + * feature is in a FreeType release version and version macros can be used + * to test for availability. + */ +#ifdef TT_CONFIG_OPTION_COLOR_LAYERS +#define TT_SUPPORT_COLRV1 +#endif + +/* + * Check CFF darkening parameters. The checks are the same as in function + * `cff_property_set` in file `cffdrivr.c`. + */ +#if CFF_CONFIG_OPTION_DARKENING_PARAMETER_X1 < 0 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_X2 < 0 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_X3 < 0 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_X4 < 0 || \ + \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y1 < 0 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y2 < 0 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y3 < 0 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y4 < 0 || \ + \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_X1 > \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_X2 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_X2 > \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_X3 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_X3 > \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_X4 || \ + \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y1 > 500 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y2 > 500 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y3 > 500 || \ + CFF_CONFIG_OPTION_DARKENING_PARAMETER_Y4 > 500 +#error "Invalid CFF darkening parameters!" +#endif + +FT_END_HEADER + +#endif /* FTOPTION_H_ */ + +/* END */ diff --git a/freetype/test/main.zig b/freetype/test/main.zig new file mode 100644 index 00000000..c03b239b --- /dev/null +++ b/freetype/test/main.zig @@ -0,0 +1,54 @@ +const freetype = @import("freetype"); + +const firasnas_font_path = "test/assets/FiraSans-Regular.ttf"; +const firasnas_font_data = @embedFile("assets/FiraSans-Regular.ttf"); + +test "new face from file" { + const lib = try freetype.Library.init(); + _ = try lib.newFace(firasnas_font_path, 0); +} + +test "new face from memory" { + const lib = try freetype.Library.init(); + _ = try lib.newFaceMemory(firasnas_font_data, 0); +} + +test "new stroker" { + const lib = try freetype.Library.init(); + _ = try lib.newStroker(); +} + +test "set lcd filter" { + if (@hasDecl(freetype.C, "FT_CONFIG_OPTION_SUBPIXEL_RENDERING")) { + const lib = try freetype.Library.init(); + try lib.setLcdFilter(.default); + } else { + return error.SkipZigTest; + } +} + +test "load glyph" { + const lib = try freetype.Library.init(); + const face = try lib.newFace(firasnas_font_path, 0); + + try face.setPixelSizes(100, 100); + try face.setCharSize(10 * 10, 0, 72, 0); + + try face.loadGlyph(205, .{}); + try face.loadChar('A', .{}); + + face.deinit(); +} + +test "attach file" { + const lib = try freetype.Library.init(); + const face = try lib.newFace("test/assets/DejaVuSans.pfb", 0); + try face.attachFile("test/assets/DejaVuSans.pfm"); +} + +test "attach from memory" { + const lib = try freetype.Library.init(); + const face = try lib.newFace("test/assets/DejaVuSans.pfb", 0); + const file = @embedFile("assets/DejaVuSans.pfm"); + try face.attachMemory(file); +}