mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 16:56:09 +03:00
font: Group maintains face ownership
This commit is contained in:
@ -22,6 +22,7 @@ const Glyph = @import("main.zig").Glyph;
|
|||||||
const Style = @import("main.zig").Style;
|
const Style = @import("main.zig").Style;
|
||||||
const Presentation = @import("main.zig").Presentation;
|
const Presentation = @import("main.zig").Presentation;
|
||||||
const options = @import("main.zig").options;
|
const options = @import("main.zig").options;
|
||||||
|
const quirks = @import("../quirks.zig");
|
||||||
|
|
||||||
const log = std.log.scoped(.font_group);
|
const log = std.log.scoped(.font_group);
|
||||||
|
|
||||||
@ -30,7 +31,18 @@ const log = std.log.scoped(.font_group);
|
|||||||
// usually only one font group for the entire process so this isn't the
|
// usually only one font group for the entire process so this isn't the
|
||||||
// most important memory efficiency we can look for. This is totally opaque
|
// most important memory efficiency we can look for. This is totally opaque
|
||||||
// to the user so we can change this later.
|
// to the user so we can change this later.
|
||||||
const StyleArray = std.EnumArray(Style, std.ArrayListUnmanaged(DeferredFace));
|
const StyleArray = std.EnumArray(Style, std.ArrayListUnmanaged(StyleElem));
|
||||||
|
const StyleElem = union(enum) {
|
||||||
|
deferred: DeferredFace, // Not loaded
|
||||||
|
loaded: Face, // Loaded
|
||||||
|
|
||||||
|
pub fn deinit(self: *StyleElem) void {
|
||||||
|
switch (self.*) {
|
||||||
|
.deferred => |*v| v.deinit(),
|
||||||
|
.loaded => |*v| v.deinit(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/// The allocator for this group
|
/// The allocator for this group
|
||||||
alloc: Allocator,
|
alloc: Allocator,
|
||||||
@ -92,7 +104,7 @@ pub fn addFace(self: *Group, alloc: Allocator, style: Style, face: DeferredFace)
|
|||||||
// We have some special indexes so we must never pass those.
|
// We have some special indexes so we must never pass those.
|
||||||
if (list.items.len >= FontIndex.Special.start - 1) return error.GroupFull;
|
if (list.items.len >= FontIndex.Special.start - 1) return error.GroupFull;
|
||||||
|
|
||||||
try list.append(alloc, face);
|
try list.append(alloc, .{ .deferred = face });
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the face for the given style. This will always return the first
|
/// Get the face for the given style. This will always return the first
|
||||||
@ -113,10 +125,10 @@ pub fn setSize(self: *Group, size: font.face.DesiredSize) !void {
|
|||||||
// Resize all our faces that are loaded
|
// Resize all our faces that are loaded
|
||||||
var it = self.faces.iterator();
|
var it = self.faces.iterator();
|
||||||
while (it.next()) |entry| {
|
while (it.next()) |entry| {
|
||||||
for (entry.value.items) |*deferred| {
|
for (entry.value.items) |*elem| switch (elem.*) {
|
||||||
if (!deferred.loaded()) continue;
|
.deferred => continue,
|
||||||
try deferred.face.?.setSize(size);
|
.loaded => |*f| try f.setSize(size),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set our size for future loads
|
// Set our size for future loads
|
||||||
@ -231,8 +243,16 @@ pub fn indexForCodepoint(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn indexForCodepointExact(self: Group, cp: u32, style: Style, p: ?Presentation) ?FontIndex {
|
fn indexForCodepointExact(self: Group, cp: u32, style: Style, p: ?Presentation) ?FontIndex {
|
||||||
for (self.faces.get(style).items, 0..) |deferred, i| {
|
for (self.faces.get(style).items, 0..) |elem, i| {
|
||||||
if (deferred.hasCodepoint(cp, p)) {
|
const has_cp = switch (elem) {
|
||||||
|
.deferred => |v| v.hasCodepoint(cp, p),
|
||||||
|
.loaded => |face| loaded: {
|
||||||
|
if (p) |desired| if (face.presentation != desired) break :loaded false;
|
||||||
|
break :loaded face.glyphIndex(cp) != null;
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
if (has_cp) {
|
||||||
return FontIndex{
|
return FontIndex{
|
||||||
.style = style,
|
.style = style,
|
||||||
.idx = @intCast(i),
|
.idx = @intCast(i),
|
||||||
@ -246,7 +266,7 @@ fn indexForCodepointExact(self: Group, cp: u32, style: Style, p: ?Presentation)
|
|||||||
|
|
||||||
/// Returns the presentation for a specific font index. This is useful for
|
/// Returns the presentation for a specific font index. This is useful for
|
||||||
/// determining what atlas is needed.
|
/// determining what atlas is needed.
|
||||||
pub fn presentationFromIndex(self: Group, index: FontIndex) !font.Presentation {
|
pub fn presentationFromIndex(self: *Group, index: FontIndex) !font.Presentation {
|
||||||
if (index.special()) |sp| switch (sp) {
|
if (index.special()) |sp| switch (sp) {
|
||||||
.sprite => return .text,
|
.sprite => return .text,
|
||||||
};
|
};
|
||||||
@ -256,12 +276,21 @@ pub fn presentationFromIndex(self: Group, index: FontIndex) !font.Presentation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Return the Face represented by a given FontIndex. Note that special
|
/// Return the Face represented by a given FontIndex. Note that special
|
||||||
/// fonts (i.e. box glyphs) do not have a face.
|
/// fonts (i.e. box glyphs) do not have a face. The returned face pointer is
|
||||||
pub fn faceFromIndex(self: Group, index: FontIndex) !*Face {
|
/// only valid until the set of faces change.
|
||||||
|
pub fn faceFromIndex(self: *Group, index: FontIndex) !*Face {
|
||||||
if (index.special() != null) return error.SpecialHasNoFace;
|
if (index.special() != null) return error.SpecialHasNoFace;
|
||||||
const deferred = &self.faces.get(index.style).items[@intCast(index.idx)];
|
const list = self.faces.getPtr(index.style);
|
||||||
try deferred.load(self.lib, self.size);
|
const item = &list.items[@intCast(index.idx)];
|
||||||
return &deferred.face.?;
|
return switch (item.*) {
|
||||||
|
.deferred => |*d| deferred: {
|
||||||
|
try d.load(self.lib, self.size);
|
||||||
|
item.* = .{ .loaded = d.face.? };
|
||||||
|
break :deferred &item.loaded;
|
||||||
|
},
|
||||||
|
|
||||||
|
.loaded => |*f| f,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Render a glyph by glyph index into the given font atlas and return
|
/// Render a glyph by glyph index into the given font atlas and return
|
||||||
@ -276,7 +305,7 @@ pub fn faceFromIndex(self: Group, index: FontIndex) !*Face {
|
|||||||
/// doing text shaping, the text shaping library (i.e. HarfBuzz) will automatically
|
/// doing text shaping, the text shaping library (i.e. HarfBuzz) will automatically
|
||||||
/// determine glyph indexes for a text run.
|
/// determine glyph indexes for a text run.
|
||||||
pub fn renderGlyph(
|
pub fn renderGlyph(
|
||||||
self: Group,
|
self: *Group,
|
||||||
alloc: Allocator,
|
alloc: Allocator,
|
||||||
atlas: *font.Atlas,
|
atlas: *font.Atlas,
|
||||||
index: FontIndex,
|
index: FontIndex,
|
||||||
@ -292,9 +321,8 @@ pub fn renderGlyph(
|
|||||||
),
|
),
|
||||||
};
|
};
|
||||||
|
|
||||||
const face = &self.faces.get(index.style).items[@intCast(index.idx)];
|
const face = try self.faceFromIndex(index);
|
||||||
try face.load(self.lib, self.size);
|
const glyph = try face.renderGlyph(alloc, atlas, glyph_index, opts);
|
||||||
const glyph = try face.face.?.renderGlyph(alloc, atlas, glyph_index, opts);
|
|
||||||
// log.warn("GLYPH={}", .{glyph});
|
// log.warn("GLYPH={}", .{glyph});
|
||||||
return glyph;
|
return glyph;
|
||||||
}
|
}
|
||||||
|
@ -187,7 +187,7 @@ test {
|
|||||||
.regular,
|
.regular,
|
||||||
DeferredFace.initLoaded(try Face.init(lib, testFont, .{ .points = 12 })),
|
DeferredFace.initLoaded(try Face.init(lib, testFont, .{ .points = 12 })),
|
||||||
);
|
);
|
||||||
const group = cache.group;
|
var group = cache.group;
|
||||||
|
|
||||||
// Visible ASCII. Do it twice to verify cache.
|
// Visible ASCII. Do it twice to verify cache.
|
||||||
var i: u32 = 32;
|
var i: u32 = 32;
|
||||||
|
Reference in New Issue
Block a user