mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-08-02 14:57:31 +03:00
core: convert surface/app to use GroupCacheSet
This commit is contained in:
31
src/App.zig
31
src/App.zig
@ -41,10 +41,9 @@ mailbox: Mailbox.Queue,
|
|||||||
/// Set to true once we're quitting. This never goes false again.
|
/// Set to true once we're quitting. This never goes false again.
|
||||||
quit: bool,
|
quit: bool,
|
||||||
|
|
||||||
/// Font discovery mechanism. This is only safe to use from the main thread.
|
/// The set of font GroupCache instances shared by surfaces with the
|
||||||
/// This is lazily initialized on the first call to fontDiscover so do
|
/// same font configuration.
|
||||||
/// not access this directly.
|
font_group_set: font.GroupCacheSet,
|
||||||
font_discover: ?font.Discover = null,
|
|
||||||
|
|
||||||
/// Initialize the main app instance. This creates the main window, sets
|
/// Initialize the main app instance. This creates the main window, sets
|
||||||
/// up the renderer state, compiles the shaders, etc. This is the primary
|
/// up the renderer state, compiles the shaders, etc. This is the primary
|
||||||
@ -55,11 +54,15 @@ pub fn create(
|
|||||||
var app = try alloc.create(App);
|
var app = try alloc.create(App);
|
||||||
errdefer alloc.destroy(app);
|
errdefer alloc.destroy(app);
|
||||||
|
|
||||||
|
var font_group_set = try font.GroupCacheSet.init(alloc);
|
||||||
|
errdefer font_group_set.deinit();
|
||||||
|
|
||||||
app.* = .{
|
app.* = .{
|
||||||
.alloc = alloc,
|
.alloc = alloc,
|
||||||
.surfaces = .{},
|
.surfaces = .{},
|
||||||
.mailbox = .{},
|
.mailbox = .{},
|
||||||
.quit = false,
|
.quit = false,
|
||||||
|
.font_group_set = font_group_set,
|
||||||
};
|
};
|
||||||
errdefer app.surfaces.deinit(alloc);
|
errdefer app.surfaces.deinit(alloc);
|
||||||
|
|
||||||
@ -71,9 +74,9 @@ pub fn destroy(self: *App) void {
|
|||||||
for (self.surfaces.items) |surface| surface.deinit();
|
for (self.surfaces.items) |surface| surface.deinit();
|
||||||
self.surfaces.deinit(self.alloc);
|
self.surfaces.deinit(self.alloc);
|
||||||
|
|
||||||
if (comptime font.Discover != void) {
|
// Clean up our font group cache
|
||||||
if (self.font_discover) |*v| v.deinit();
|
// TODO(fontmem): assert all ref counts are zero
|
||||||
}
|
self.font_group_set.deinit();
|
||||||
|
|
||||||
self.alloc.destroy(self);
|
self.alloc.destroy(self);
|
||||||
}
|
}
|
||||||
@ -166,20 +169,6 @@ pub fn needsConfirmQuit(self: *const App) bool {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initialize once and return the font discovery mechanism. This remains
|
|
||||||
/// initialized throughout the lifetime of the application because some
|
|
||||||
/// font discovery mechanisms (i.e. fontconfig) are unsafe to reinit.
|
|
||||||
pub fn fontDiscover(self: *App) !?*font.Discover {
|
|
||||||
// If we're built without a font discovery mechanism, return null
|
|
||||||
if (comptime font.Discover == void) return null;
|
|
||||||
|
|
||||||
// If we initialized, use it
|
|
||||||
if (self.font_discover) |*v| return v;
|
|
||||||
|
|
||||||
self.font_discover = font.Discover.init();
|
|
||||||
return &self.font_discover.?;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Drain the mailbox.
|
/// Drain the mailbox.
|
||||||
fn drainMailbox(self: *App, rt_app: *apprt.App) !void {
|
fn drainMailbox(self: *App, rt_app: *apprt.App) !void {
|
||||||
while (self.mailbox.pop()) |message| {
|
while (self.mailbox.pop()) |message| {
|
||||||
|
122
src/Surface.zig
122
src/Surface.zig
@ -54,8 +54,6 @@ rt_app: *apprt.runtime.App,
|
|||||||
rt_surface: *apprt.runtime.Surface,
|
rt_surface: *apprt.runtime.Surface,
|
||||||
|
|
||||||
/// The font structures
|
/// The font structures
|
||||||
font_lib: font.Library,
|
|
||||||
font_group: *font.GroupCache,
|
|
||||||
font_size: font.face.DesiredSize,
|
font_size: font.face.DesiredSize,
|
||||||
|
|
||||||
/// The renderer for this surface.
|
/// The renderer for this surface.
|
||||||
@ -320,117 +318,9 @@ pub fn init(
|
|||||||
.ydpi = @intFromFloat(y_dpi),
|
.ydpi = @intFromFloat(y_dpi),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Create our font group key. This is used to determine if we have
|
// Setup our font group. This will reuse an existing font group if
|
||||||
// a cached font group we can use already. Otherwise, this can be
|
// it was already loaded.
|
||||||
// used to build the group.
|
const font_group = try app.font_group_set.groupInit(config, font_size);
|
||||||
var font_group_key = try font.GroupCacheSet.Key.init(alloc, config);
|
|
||||||
defer font_group_key.deinit();
|
|
||||||
|
|
||||||
// Find all the fonts for this surface
|
|
||||||
//
|
|
||||||
// Future: we can share the font group amongst all surfaces to save
|
|
||||||
// some new surface init time and some memory. This will require making
|
|
||||||
// thread-safe changes to font structs.
|
|
||||||
var font_lib = try font.Library.init();
|
|
||||||
errdefer font_lib.deinit();
|
|
||||||
var font_group = try alloc.create(font.GroupCache);
|
|
||||||
errdefer alloc.destroy(font_group);
|
|
||||||
font_group.* = try font.GroupCache.init(alloc, group: {
|
|
||||||
var group = try font.Group.init(alloc, font_lib, font_size);
|
|
||||||
errdefer group.deinit();
|
|
||||||
group.metric_modifiers = font_group_key.metric_modifiers;
|
|
||||||
group.codepoint_map = font_group_key.codepoint_map;
|
|
||||||
|
|
||||||
// Set our styles
|
|
||||||
group.styles.set(.bold, config.@"font-style-bold" != .false);
|
|
||||||
group.styles.set(.italic, config.@"font-style-italic" != .false);
|
|
||||||
group.styles.set(.bold_italic, config.@"font-style-bold-italic" != .false);
|
|
||||||
|
|
||||||
// Search for fonts
|
|
||||||
if (font.Discover != void) discover: {
|
|
||||||
const disco = try app.fontDiscover() orelse {
|
|
||||||
log.warn("font discovery not available, cannot search for fonts", .{});
|
|
||||||
break :discover;
|
|
||||||
};
|
|
||||||
group.discover = disco;
|
|
||||||
|
|
||||||
// A buffer we use to store the font names for logging.
|
|
||||||
var name_buf: [256]u8 = undefined;
|
|
||||||
|
|
||||||
inline for (@typeInfo(font.Style).Enum.fields) |field| {
|
|
||||||
const style = @field(font.Style, field.name);
|
|
||||||
for (font_group_key.descriptorsForStyle(style)) |desc| {
|
|
||||||
var disco_it = try disco.discover(alloc, desc);
|
|
||||||
defer disco_it.deinit();
|
|
||||||
if (try disco_it.next()) |face| {
|
|
||||||
log.info("font {s}: {s}", .{
|
|
||||||
field.name,
|
|
||||||
try face.name(&name_buf),
|
|
||||||
});
|
|
||||||
_ = try group.addFace(style, .{ .deferred = face });
|
|
||||||
} else log.warn("font-family {s} not found: {s}", .{
|
|
||||||
field.name,
|
|
||||||
desc.family.?,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Our built-in font will be used as a backup
|
|
||||||
_ = try group.addFace(
|
|
||||||
.regular,
|
|
||||||
.{ .fallback_loaded = try font.Face.init(
|
|
||||||
font_lib,
|
|
||||||
face_ttf,
|
|
||||||
group.faceOptions(),
|
|
||||||
) },
|
|
||||||
);
|
|
||||||
_ = try group.addFace(
|
|
||||||
.bold,
|
|
||||||
.{ .fallback_loaded = try font.Face.init(
|
|
||||||
font_lib,
|
|
||||||
face_bold_ttf,
|
|
||||||
group.faceOptions(),
|
|
||||||
) },
|
|
||||||
);
|
|
||||||
|
|
||||||
// Auto-italicize if we have to.
|
|
||||||
try group.italicize();
|
|
||||||
|
|
||||||
// On macOS, always search for and add the Apple Emoji font
|
|
||||||
// as our preferred emoji font for fallback. We do this in case
|
|
||||||
// people add other emoji fonts to their system, we always want to
|
|
||||||
// prefer the official one. Users can override this by explicitly
|
|
||||||
// specifying a font-family for emoji.
|
|
||||||
if (comptime builtin.target.isDarwin()) apple_emoji: {
|
|
||||||
const disco = group.discover orelse break :apple_emoji;
|
|
||||||
var disco_it = try disco.discover(alloc, .{
|
|
||||||
.family = "Apple Color Emoji",
|
|
||||||
});
|
|
||||||
defer disco_it.deinit();
|
|
||||||
if (try disco_it.next()) |face| {
|
|
||||||
_ = try group.addFace(.regular, .{ .fallback_deferred = face });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Emoji fallback. We don't include this on Mac since Mac is expected
|
|
||||||
// to always have the Apple Emoji available on the system.
|
|
||||||
if (comptime !builtin.target.isDarwin() or font.Discover == void) {
|
|
||||||
_ = try group.addFace(
|
|
||||||
.regular,
|
|
||||||
.{ .fallback_loaded = try font.Face.init(font_lib, face_emoji_ttf, group.faceOptions()) },
|
|
||||||
);
|
|
||||||
_ = try group.addFace(
|
|
||||||
.regular,
|
|
||||||
.{ .fallback_loaded = try font.Face.init(font_lib, face_emoji_text_ttf, group.faceOptions()) },
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
break :group group;
|
|
||||||
});
|
|
||||||
errdefer font_group.deinit(alloc);
|
|
||||||
|
|
||||||
log.info("font loading complete, any non-logged faces are using the built-in font", .{});
|
|
||||||
|
|
||||||
// Pre-calculate our initial cell size ourselves.
|
// Pre-calculate our initial cell size ourselves.
|
||||||
const cell_size = try renderer.CellSize.init(alloc, font_group);
|
const cell_size = try renderer.CellSize.init(alloc, font_group);
|
||||||
@ -516,8 +406,6 @@ pub fn init(
|
|||||||
.app = app,
|
.app = app,
|
||||||
.rt_app = rt_app,
|
.rt_app = rt_app,
|
||||||
.rt_surface = rt_surface,
|
.rt_surface = rt_surface,
|
||||||
.font_lib = font_lib,
|
|
||||||
.font_group = font_group,
|
|
||||||
.font_size = font_size,
|
.font_size = font_size,
|
||||||
.renderer = renderer_impl,
|
.renderer = renderer_impl,
|
||||||
.renderer_thread = render_thread,
|
.renderer_thread = render_thread,
|
||||||
@ -632,10 +520,6 @@ pub fn deinit(self: *Surface) void {
|
|||||||
self.io_thread.deinit();
|
self.io_thread.deinit();
|
||||||
self.io.deinit();
|
self.io.deinit();
|
||||||
|
|
||||||
self.font_group.deinit(self.alloc);
|
|
||||||
self.font_lib.deinit();
|
|
||||||
self.alloc.destroy(self.font_group);
|
|
||||||
|
|
||||||
if (self.inspector) |v| {
|
if (self.inspector) |v| {
|
||||||
v.deinit();
|
v.deinit();
|
||||||
self.alloc.destroy(v);
|
self.alloc.destroy(v);
|
||||||
|
@ -87,7 +87,7 @@ pub fn groupInit(
|
|||||||
var key = try Key.init(self.alloc, config);
|
var key = try Key.init(self.alloc, config);
|
||||||
errdefer key.deinit();
|
errdefer key.deinit();
|
||||||
|
|
||||||
const gop = try self.map.getOrPut(key);
|
const gop = try self.map.getOrPut(self.alloc, key);
|
||||||
if (gop.found_existing) {
|
if (gop.found_existing) {
|
||||||
// We can deinit the key because we found a cached value.
|
// We can deinit the key because we found a cached value.
|
||||||
key.deinit();
|
key.deinit();
|
||||||
@ -205,6 +205,7 @@ pub fn groupInit(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
log.info("font loading complete, any non-logged faces are using the built-in font", .{});
|
||||||
break :group group;
|
break :group group;
|
||||||
});
|
});
|
||||||
errdefer cache.deinit(self.alloc);
|
errdefer cache.deinit(self.alloc);
|
||||||
|
Reference in New Issue
Block a user