mirror of
https://github.com/ghostty-org/ghostty.git
synced 2026-06-06 03:44:22 +00:00
font: DeferredFace can no longer represent a loaded face
This commit is contained in:
@@ -30,9 +30,6 @@ const FaceState = switch (options.backend) {
|
||||
.web_canvas => WebCanvas,
|
||||
};
|
||||
|
||||
/// The loaded face (once loaded).
|
||||
face: ?Face = null,
|
||||
|
||||
/// Fontconfig
|
||||
fc: if (options.backend == .fontconfig_freetype) ?Fontconfig else void =
|
||||
if (options.backend == .fontconfig_freetype) null else {},
|
||||
@@ -91,14 +88,7 @@ pub const WebCanvas = struct {
|
||||
}
|
||||
};
|
||||
|
||||
/// Initialize a deferred face that is already pre-loaded. The deferred face
|
||||
/// takes ownership over the loaded face, deinit will deinit the loaded face.
|
||||
pub fn initLoaded(face: Face) DeferredFace {
|
||||
return .{ .face = face };
|
||||
}
|
||||
|
||||
pub fn deinit(self: *DeferredFace) void {
|
||||
if (self.face) |*face| face.deinit();
|
||||
switch (options.backend) {
|
||||
.fontconfig_freetype => if (self.fc) |*fc| fc.deinit(),
|
||||
.coretext, .coretext_freetype => if (self.ct) |*ct| ct.deinit(),
|
||||
@@ -108,11 +98,6 @@ pub fn deinit(self: *DeferredFace) void {
|
||||
self.* = undefined;
|
||||
}
|
||||
|
||||
/// Returns true if the face has been loaded.
|
||||
pub inline fn loaded(self: DeferredFace) bool {
|
||||
return self.face != null;
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
@@ -152,69 +137,48 @@ pub fn load(
|
||||
self: *DeferredFace,
|
||||
lib: Library,
|
||||
size: font.face.DesiredSize,
|
||||
) !void {
|
||||
// No-op if we already loaded
|
||||
if (self.face != null) return;
|
||||
|
||||
switch (options.backend) {
|
||||
.fontconfig_freetype => {
|
||||
try self.loadFontconfig(lib, size);
|
||||
return;
|
||||
},
|
||||
|
||||
.coretext => {
|
||||
try self.loadCoreText(lib, size);
|
||||
return;
|
||||
},
|
||||
|
||||
.coretext_freetype => {
|
||||
try self.loadCoreTextFreetype(lib, size);
|
||||
return;
|
||||
},
|
||||
|
||||
.web_canvas => {
|
||||
try self.loadWebCanvas(size);
|
||||
return;
|
||||
},
|
||||
) !Face {
|
||||
return switch (options.backend) {
|
||||
.fontconfig_freetype => try self.loadFontconfig(lib, size),
|
||||
.coretext => try self.loadCoreText(lib, size),
|
||||
.coretext_freetype => try self.loadCoreTextFreetype(lib, size),
|
||||
.web_canvas => try self.loadWebCanvas(size),
|
||||
|
||||
// Unreachable because we must be already loaded or have the
|
||||
// proper configuration for one of the other deferred mechanisms.
|
||||
.freetype => unreachable,
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn loadFontconfig(
|
||||
self: *DeferredFace,
|
||||
lib: Library,
|
||||
size: font.face.DesiredSize,
|
||||
) !void {
|
||||
assert(self.face == null);
|
||||
) !Face {
|
||||
const fc = self.fc.?;
|
||||
|
||||
// Filename and index for our face so we can load it
|
||||
const filename = (try fc.pattern.get(.file, 0)).string;
|
||||
const face_index = (try fc.pattern.get(.index, 0)).integer;
|
||||
|
||||
self.face = try Face.initFile(lib, filename, face_index, size);
|
||||
return try Face.initFile(lib, filename, face_index, size);
|
||||
}
|
||||
|
||||
fn loadCoreText(
|
||||
self: *DeferredFace,
|
||||
lib: Library,
|
||||
size: font.face.DesiredSize,
|
||||
) !void {
|
||||
) !Face {
|
||||
_ = lib;
|
||||
assert(self.face == null);
|
||||
const ct = self.ct.?;
|
||||
self.face = try Face.initFontCopy(ct.font, size);
|
||||
return try Face.initFontCopy(ct.font, size);
|
||||
}
|
||||
|
||||
fn loadCoreTextFreetype(
|
||||
self: *DeferredFace,
|
||||
lib: Library,
|
||||
size: font.face.DesiredSize,
|
||||
) !void {
|
||||
assert(self.face == null);
|
||||
) !Face {
|
||||
const ct = self.ct.?;
|
||||
|
||||
// Get the URL for the font so we can get the filepath
|
||||
@@ -246,16 +210,15 @@ fn loadCoreTextFreetype(
|
||||
// TODO: face index 0 is not correct long term and we should switch
|
||||
// to using CoreText for rendering, too.
|
||||
//std.log.warn("path={s}", .{path_slice});
|
||||
self.face = try Face.initFile(lib, buf[0..path_slice.len :0], 0, size);
|
||||
return try Face.initFile(lib, buf[0..path_slice.len :0], 0, size);
|
||||
}
|
||||
|
||||
fn loadWebCanvas(
|
||||
self: *DeferredFace,
|
||||
size: font.face.DesiredSize,
|
||||
) !void {
|
||||
assert(self.face == null);
|
||||
) !Face {
|
||||
const wc = self.wc.?;
|
||||
self.face = try Face.initNamed(wc.alloc, wc.font_str, size, wc.presentation);
|
||||
return try Face.initNamed(wc.alloc, wc.font_str, size, wc.presentation);
|
||||
}
|
||||
|
||||
/// Returns true if this face can satisfy the given codepoint and
|
||||
@@ -266,12 +229,6 @@ fn loadWebCanvas(
|
||||
/// discovery mechanism (i.e. fontconfig). If no discovery is used,
|
||||
/// the face is always expected to be loaded.
|
||||
pub fn hasCodepoint(self: DeferredFace, cp: u32, p: ?Presentation) bool {
|
||||
// If we have the face, use the face.
|
||||
if (self.face) |face| {
|
||||
if (p) |desired| if (face.presentation != desired) return false;
|
||||
return face.glyphIndex(cp) != null;
|
||||
}
|
||||
|
||||
switch (options.backend) {
|
||||
.fontconfig_freetype => {
|
||||
// If we are using fontconfig, use the fontconfig metadata to
|
||||
@@ -388,30 +345,8 @@ pub const Wasm = struct {
|
||||
return;
|
||||
};
|
||||
}
|
||||
|
||||
/// Caller should not free this, the face is owned by the deferred face.
|
||||
export fn deferred_face_face(self: *DeferredFace) ?*Face {
|
||||
assert(self.loaded());
|
||||
return &self.face.?;
|
||||
}
|
||||
};
|
||||
|
||||
test "preloaded" {
|
||||
const testing = std.testing;
|
||||
const testFont = @import("test.zig").fontRegular;
|
||||
|
||||
var lib = try Library.init();
|
||||
defer lib.deinit();
|
||||
|
||||
var face = try Face.init(lib, testFont, .{ .points = 12 });
|
||||
errdefer face.deinit();
|
||||
|
||||
var def = initLoaded(face);
|
||||
defer def.deinit();
|
||||
|
||||
try testing.expect(def.hasCodepoint(' ', null));
|
||||
}
|
||||
|
||||
test "fontconfig" {
|
||||
if (options.backend != .fontconfig_freetype) return error.SkipZigTest;
|
||||
|
||||
@@ -430,7 +365,6 @@ test "fontconfig" {
|
||||
break :def (try it.next()).?;
|
||||
};
|
||||
defer def.deinit();
|
||||
try testing.expect(!def.loaded());
|
||||
|
||||
// Verify we can get the name
|
||||
const n = try def.name();
|
||||
@@ -460,7 +394,6 @@ test "coretext" {
|
||||
break :def (try it.next()).?;
|
||||
};
|
||||
defer def.deinit();
|
||||
try testing.expect(!def.loaded());
|
||||
try testing.expect(def.hasCodepoint(' ', null));
|
||||
|
||||
// Verify we can get the name
|
||||
@@ -468,7 +401,6 @@ test "coretext" {
|
||||
try testing.expect(n.len > 0);
|
||||
|
||||
// Load it and verify it works
|
||||
try def.load(lib, .{ .points = 12 });
|
||||
try testing.expect(def.hasCodepoint(' ', null));
|
||||
try testing.expect(def.face.?.glyphIndex(' ') != null);
|
||||
const face = try def.load(lib, .{ .points = 12 });
|
||||
try testing.expect(face.glyphIndex(' ') != null);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user