font: set "backend" enum vs booleans

This commit is contained in:
Mitchell Hashimoto
2022-10-02 09:41:37 -07:00
parent 12c9482d48
commit f41cbf228b
4 changed files with 89 additions and 65 deletions

View File

@ -19,10 +19,12 @@ const Presentation = @import("main.zig").Presentation;
face: ?Face = null,
/// Fontconfig
fc: if (options.fontconfig) ?Fontconfig else void = if (options.fontconfig) null else {},
fc: if (options.backend == .fontconfig_freetype) ?Fontconfig else void =
if (options.backend == .fontconfig_freetype) null else {},
/// CoreText
ct: if (options.coretext) ?CoreText else void = if (options.coretext) null else {},
ct: if (options.backend == .coretext) ?CoreText else void =
if (options.backend == .coretext) null else {},
/// Fontconfig specific data. This is only present if building with fontconfig.
pub const Fontconfig = struct {
@ -61,8 +63,11 @@ pub fn initLoaded(face: Face) DeferredFace {
pub fn deinit(self: *DeferredFace) void {
if (self.face) |*face| face.deinit();
if (options.fontconfig) if (self.fc) |*fc| fc.deinit();
if (options.coretext) if (self.ct) |*ct| ct.deinit();
switch (options.backend) {
.fontconfig_freetype => if (self.fc) |*fc| fc.deinit(),
.coretext => if (self.ct) |*ct| ct.deinit(),
.freetype => {},
}
self.* = undefined;
}
@ -74,16 +79,16 @@ pub inline fn loaded(self: DeferredFace) bool {
/// Returns the name of this face. The memory is always owned by the
/// face so it doesn't have to be freed.
pub fn name(self: DeferredFace) ![:0]const u8 {
if (options.fontconfig) {
if (self.fc) |fc|
return (try fc.pattern.get(.fullname, 0)).string;
}
switch (options.backend) {
.fontconfig_freetype => if (self.fc) |fc|
return (try fc.pattern.get(.fullname, 0)).string,
if (options.coretext) {
if (self.ct) |ct| {
.coretext => if (self.ct) |ct| {
const display_name = ct.font.copyDisplayName();
return display_name.cstringPtr(.utf8) orelse "<unsupported internal encoding>";
}
},
.freetype => {},
}
return "TODO: built-in font names";
@ -98,19 +103,21 @@ pub fn load(
// No-op if we already loaded
if (self.face != null) return;
if (options.fontconfig) {
switch (options.backend) {
.fontconfig_freetype => {
try self.loadFontconfig(lib, size);
return;
}
},
if (options.coretext) {
.coretext => {
try self.loadCoreText(lib, size);
return;
}
},
// Unreachable because we must be already loaded or have the
// proper configuration for one of the other deferred mechanisms.
unreachable;
.freetype => unreachable,
}
}
fn loadFontconfig(
@ -181,9 +188,10 @@ pub fn hasCodepoint(self: DeferredFace, cp: u32, p: ?Presentation) bool {
return face.glyphIndex(cp) != null;
}
switch (options.backend) {
.fontconfig_freetype => {
// If we are using fontconfig, use the fontconfig metadata to
// avoid loading the face.
if (options.fontconfig) {
if (self.fc) |fc| {
// Check if char exists
if (!fc.charset.hasChar(cp)) return false;
@ -201,10 +209,10 @@ pub fn hasCodepoint(self: DeferredFace, cp: u32, p: ?Presentation) bool {
return true;
}
}
},
.coretext => {
// If we are using coretext, we check the loaded CT font.
if (options.coretext) {
if (self.ct) |ct| {
// Turn UTF-32 into UTF-16 for CT API
var unichars: [2]u16 = undefined;
@ -215,6 +223,9 @@ pub fn hasCodepoint(self: DeferredFace, cp: u32, p: ?Presentation) bool {
var glyphs = [2]macos.graphics.Glyph{ 0, 0 };
return ct.font.getGlyphsForCharacters(unichars[0..len], glyphs[0..len]);
}
},
.freetype => {},
}
// This is unreachable because discovery mechanisms terminate, and
@ -239,7 +250,7 @@ test "preloaded" {
}
test "fontconfig" {
if (!options.fontconfig) return error.SkipZigTest;
if (options.backend != .fontconfig_freetype) return error.SkipZigTest;
const discovery = @import("main.zig").discovery;
const testing = std.testing;
@ -269,7 +280,7 @@ test "fontconfig" {
}
test "coretext" {
if (!options.coretext) return error.SkipZigTest;
if (options.backend != .coretext) return error.SkipZigTest;
const discovery = @import("main.zig").discovery;
const testing = std.testing;

View File

@ -224,7 +224,7 @@ test {
}
test {
if (!options.fontconfig) return error.SkipZigTest;
if (options.backend != .fontconfig_freetype) return error.SkipZigTest;
const testing = std.testing;
const alloc = testing.allocator;

View File

@ -9,12 +9,11 @@ const DeferredFace = @import("main.zig").DeferredFace;
const log = std.log.named(.discovery);
/// Discover implementation for the compile options.
pub const Discover = if (options.fontconfig)
Fontconfig
else if (options.coretext)
CoreText
else
void;
pub const Discover = switch (options.backend) {
.fontconfig_freetype => Fontconfig,
.coretext => CoreText,
else => void,
};
/// Descriptor is used to search for fonts. The only required field
/// is "family". The rest are ignored unless they're set to a non-zero
@ -273,7 +272,7 @@ pub const CoreText = struct {
};
test "fontconfig" {
if (!options.fontconfig) return error.SkipZigTest;
if (options.backend != .fontconfig_freetype) return error.SkipZigTest;
const testing = std.testing;
@ -286,7 +285,7 @@ test "fontconfig" {
}
test "core text" {
if (!options.coretext) return error.SkipZigTest;
if (options.backend != .coretext) return error.SkipZigTest;
const testing = std.testing;

View File

@ -14,11 +14,25 @@ pub const Discover = discovery.Discover;
/// Build options
pub const options: struct {
coretext: bool = false,
fontconfig: bool = false,
backend: Backend,
} = .{
.coretext = build_options.coretext,
.fontconfig = build_options.fontconfig,
.backend = if (build_options.coretext)
.coretext
else if (build_options.fontconfig)
.fontconfig_freetype
else
.freetype,
};
pub const Backend = enum {
/// FreeType for font rendering with no font discovery enabled.
freetype,
/// Fontconfig for font discovery and FreeType for font rendering.
fontconfig_freetype,
/// CoreText for both font discovery and rendering (macOS).
coretext,
};
/// The styles that a family can take.