From 2a74330911bb9cb000f5c2671b0854da683e505d Mon Sep 17 00:00:00 2001 From: Mitchell Hashimoto Date: Mon, 5 Dec 2022 16:08:20 -0800 Subject: [PATCH] font: begin making Group work with wasm --- build.zig | 2 ++ src/font/DeferredFace.zig | 22 ++++++++++---------- src/font/Group.zig | 20 +++++++++++++++++++ src/font/Library.zig | 19 ------------------ src/font/face.zig | 10 ++++++---- src/font/library.zig | 42 +++++++++++++++++++++++++++++++++++++++ src/font/main.zig | 8 ++++++-- 7 files changed, 86 insertions(+), 37 deletions(-) delete mode 100644 src/font/Library.zig create mode 100644 src/font/library.zig diff --git a/build.zig b/build.zig index fadf1539b..ee98edeb0 100644 --- a/build.zig +++ b/build.zig @@ -121,6 +121,8 @@ pub fn build(b: *std.build.Builder) !void { wasm.setBuildMode(mode); wasm.setOutputDir("zig-out"); + wasm.addOptions("build_options", exe_options); + // Wasm-specific deps wasm.addPackage(js.pkg); wasm.addPackage(tracylib.pkg); diff --git a/src/font/DeferredFace.zig b/src/font/DeferredFace.zig index 9ae816fa2..0c8fd709e 100644 --- a/src/font/DeferredFace.zig +++ b/src/font/DeferredFace.zig @@ -24,8 +24,8 @@ fc: if (options.backend == .fontconfig_freetype) ?Fontconfig else void = if (options.backend == .fontconfig_freetype) null else {}, /// CoreText -ct: if (options.backend == .coretext) ?CoreText else void = - if (options.backend == .coretext) null else {}, +ct: if (font.Discover == font.discovery.CoreText) ?CoreText else void = + if (font.Discover == font.discovery.CoreText) null else {}, /// Fontconfig specific data. This is only present if building with fontconfig. pub const Fontconfig = struct { @@ -66,7 +66,7 @@ pub fn deinit(self: *DeferredFace) void { if (self.face) |*face| face.deinit(); switch (options.backend) { .fontconfig_freetype => if (self.fc) |*fc| fc.deinit(), - .coretext => if (self.ct) |*ct| ct.deinit(), + .coretext, .coretext_freetype => if (self.ct) |*ct| ct.deinit(), .freetype => {}, // TODO .web_canvas => unreachable, @@ -86,7 +86,7 @@ pub fn name(self: DeferredFace) ![:0]const u8 { .fontconfig_freetype => if (self.fc) |fc| return (try fc.pattern.get(.fullname, 0)).string, - .coretext => if (self.ct) |ct| { + .coretext, .coretext_freetype => if (self.ct) |ct| { const display_name = ct.font.copyDisplayName(); return display_name.cstringPtr(.utf8) orelse ""; }, @@ -116,14 +116,12 @@ pub fn load( }, .coretext => { - // It is possible to use CoreText with Freetype so we support - // both here. - switch (font.Face) { - @import("face/freetype.zig").Face => try self.loadCoreTextFreetype(lib, size), - @import("face/coretext.zig").Face => try self.loadCoreText(lib, size), - else => unreachable, - } + try self.loadCoreText(lib, size); + return; + }, + .coretext_freetype => { + try self.loadCoreTextFreetype(lib, size); return; }, @@ -239,7 +237,7 @@ pub fn hasCodepoint(self: DeferredFace, cp: u32, p: ?Presentation) bool { } }, - .coretext => { + .coretext, .coretext_freetype => { // If we are using coretext, we check the loaded CT font. if (self.ct) |ct| { // Turn UTF-32 into UTF-16 for CT API diff --git a/src/font/Group.zig b/src/font/Group.zig index 90024bdd8..92fbf7100 100644 --- a/src/font/Group.zig +++ b/src/font/Group.zig @@ -285,6 +285,26 @@ pub fn renderGlyph( return try face.face.?.renderGlyph(alloc, atlas, glyph_index, max_height); } +/// The wasm-compatible API. +pub const Wasm = struct { + const wasm = @import("../os/wasm.zig"); + const alloc = wasm.alloc; + + export fn group_new(pts: u16) ?*Group { + return group_new_(pts) catch null; + } + + fn group_new_(pts: u16) !*Group { + var group = try Group.init(alloc, .{}, .{ .points = pts }); + errdefer group.deinit(); + + var result = try alloc.create(Group); + errdefer alloc.destroy(result); + result.* = group; + return result; + } +}; + test { const testing = std.testing; const alloc = testing.allocator; diff --git a/src/font/Library.zig b/src/font/Library.zig deleted file mode 100644 index 62a4e77d0..000000000 --- a/src/font/Library.zig +++ /dev/null @@ -1,19 +0,0 @@ -//! A library represents the shared state that the underlying font -//! library implementation(s) require per-process. -//! -//! In the future, this will be abstracted so that the underlying text -//! engine might not be Freetype and may be something like Core Text, -//! but the API will remain the same. -const Library = @This(); - -const freetype = @import("freetype"); - -lib: freetype.Library, - -pub fn init() freetype.Error!Library { - return Library{ .lib = try freetype.Library.init() }; -} - -pub fn deinit(self: *Library) void { - self.lib.deinit(); -} diff --git a/src/font/face.zig b/src/font/face.zig index e94b4ee94..b6d7465cf 100644 --- a/src/font/face.zig +++ b/src/font/face.zig @@ -6,11 +6,13 @@ pub const web_canvas = @import("face/web_canvas.zig"); /// Face implementation for the compile options. pub const Face = switch (options.backend) { - .fontconfig_freetype => freetype.Face, - .coretext => freetype.Face, - //.coretext => coretext.Face, + .freetype, + .fontconfig_freetype, + .coretext_freetype, + => freetype.Face, + + .coretext => coretext.Face, .web_canvas => web_canvas.Face, - else => unreachable, }; /// If a DPI can't be calculated, this DPI is used. This is probably diff --git a/src/font/library.zig b/src/font/library.zig new file mode 100644 index 000000000..7b7417cf4 --- /dev/null +++ b/src/font/library.zig @@ -0,0 +1,42 @@ +//! A library represents the shared state that the underlying font +//! library implementation(s) require per-process. +const builtin = @import("builtin"); +const options = @import("main.zig").options; +const freetype = @import("freetype"); +const font = @import("main.zig"); + +/// Library implementation for the compile options. +pub const Library = switch (options.backend) { + // Freetype requires a state library + .freetype, + .fontconfig_freetype, + .coretext_freetype, + => FreetypeLibrary, + + // Some backends such as CT and Canvas don't have a "library" + .coretext, + .web_canvas, + => NoopLibrary, +}; + +pub const FreetypeLibrary = struct { + lib: freetype.Library, + + pub fn init() freetype.Error!Library { + return Library{ .lib = try freetype.Library.init() }; + } + + pub fn deinit(self: *Library) void { + self.lib.deinit(); + } +}; + +pub const NoopLibrary = struct { + pub fn init() !Library { + return Library{}; + } + + pub fn deinit(self: *Library) void { + _ = self; + } +}; diff --git a/src/font/main.zig b/src/font/main.zig index 10c63d49f..008b955c0 100644 --- a/src/font/main.zig +++ b/src/font/main.zig @@ -10,16 +10,17 @@ pub const Face = face.Face; pub const Group = @import("Group.zig"); pub const GroupCache = @import("GroupCache.zig"); pub const Glyph = @import("Glyph.zig"); -pub const Library = @import("Library.zig"); pub const Shaper = @import("Shaper.zig"); pub const sprite = @import("sprite.zig"); pub const Sprite = sprite.Sprite; pub const Descriptor = discovery.Descriptor; pub const Discover = discovery.Discover; +pub usingnamespace @import("library.zig"); /// If we're targeting wasm then we export some wasm APIs. pub usingnamespace if (builtin.target.isWasm()) struct { pub usingnamespace Atlas.Wasm; + pub usingnamespace Group.Wasm; pub usingnamespace face.web_canvas.Wasm; } else struct {}; @@ -37,9 +38,12 @@ pub const Backend = enum { /// Fontconfig for font discovery and FreeType for font rendering. fontconfig_freetype, - /// CoreText for both font discovery and rendering (macOS). + /// CoreText for both font discovery for rendering (macOS). coretext, + /// CoreText for font discovery and FreeType for rendering (macOS). + coretext_freetype, + /// Use the browser font system and the Canvas API (wasm). This limits /// the available fonts to browser fonts (anything Canvas natively /// supports).