mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 08:46:08 +03:00
src/font: change Face to require font to init
This commit is contained in:
@ -193,11 +193,11 @@ pub fn init(
|
|||||||
const fam = &font_set.families.items[0];
|
const fam = &font_set.families.items[0];
|
||||||
|
|
||||||
// This is the height reported by the font face
|
// This is the height reported by the font face
|
||||||
const face_height: i32 = fam.regular.?.unitsToPxY(fam.regular.?.face.?.handle.*.height);
|
const face_height: i32 = fam.regular.?.unitsToPxY(fam.regular.?.face.handle.*.height);
|
||||||
|
|
||||||
// Determine the height of the underscore char
|
// Determine the height of the underscore char
|
||||||
const glyph = font_set.families.items[0].getGlyph('_', .regular).?;
|
const glyph = font_set.families.items[0].getGlyph('_', .regular).?;
|
||||||
var res: i32 = fam.regular.?.unitsToPxY(fam.regular.?.face.?.handle.*.ascender);
|
var res: i32 = fam.regular.?.unitsToPxY(fam.regular.?.face.handle.*.ascender);
|
||||||
res -= glyph.offset_y;
|
res -= glyph.offset_y;
|
||||||
res += @intCast(i32, glyph.height);
|
res += @intCast(i32, glyph.height);
|
||||||
|
|
||||||
@ -211,7 +211,7 @@ pub fn init(
|
|||||||
const fam = &font_set.families.items[0];
|
const fam = &font_set.families.items[0];
|
||||||
break :cell_baseline cell_height - @intToFloat(
|
break :cell_baseline cell_height - @intToFloat(
|
||||||
f32,
|
f32,
|
||||||
fam.regular.?.unitsToPxY(fam.regular.?.face.?.handle.*.ascender),
|
fam.regular.?.unitsToPxY(fam.regular.?.face.handle.*.ascender),
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
log.debug("cell dimensions w={d} h={d} baseline={d}", .{ cell_width, cell_height, cell_baseline });
|
log.debug("cell dimensions w={d} h={d} baseline={d}", .{ cell_width, cell_height, cell_baseline });
|
||||||
|
@ -21,24 +21,13 @@ const log = std.log.scoped(.font_face);
|
|||||||
library: Library,
|
library: Library,
|
||||||
|
|
||||||
/// Our font face.
|
/// Our font face.
|
||||||
face: ?freetype.Face = null,
|
face: freetype.Face,
|
||||||
|
|
||||||
/// If a DPI can't be calculated, this DPI is used. This is probably
|
/// If a DPI can't be calculated, this DPI is used. This is probably
|
||||||
/// wrong on modern devices so it is highly recommended you get the DPI
|
/// wrong on modern devices so it is highly recommended you get the DPI
|
||||||
/// using whatever platform method you can.
|
/// using whatever platform method you can.
|
||||||
pub const default_dpi = if (builtin.os.tag == .macos) 72 else 96;
|
pub const default_dpi = if (builtin.os.tag == .macos) 72 else 96;
|
||||||
|
|
||||||
pub fn init(lib: Library) !Face {
|
|
||||||
return Face{
|
|
||||||
.library = lib,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn deinit(self: *Face) void {
|
|
||||||
if (self.face) |face| face.deinit();
|
|
||||||
self.* = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The desired size for loading a font.
|
/// The desired size for loading a font.
|
||||||
pub const DesiredSize = struct {
|
pub const DesiredSize = struct {
|
||||||
// Desired size in points
|
// Desired size in points
|
||||||
@ -55,19 +44,31 @@ pub const DesiredSize = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Loads a font to use. This can only be called if a font is not already loaded.
|
/// Initialize a new font face with the given source in-memory.
|
||||||
pub fn loadFaceFromMemory(
|
pub fn init(lib: Library, source: [:0]const u8, size: DesiredSize) !Face {
|
||||||
self: *Face,
|
const face = try lib.lib.initMemoryFace(source, 0);
|
||||||
source: [:0]const u8,
|
|
||||||
size: DesiredSize,
|
|
||||||
) !void {
|
|
||||||
assert(self.face == null);
|
|
||||||
|
|
||||||
const face = try self.library.lib.initMemoryFace(source, 0);
|
|
||||||
errdefer face.deinit();
|
errdefer face.deinit();
|
||||||
|
|
||||||
try face.selectCharmap(.unicode);
|
try face.selectCharmap(.unicode);
|
||||||
|
try setSize_(face, size);
|
||||||
|
|
||||||
|
return Face{
|
||||||
|
.library = lib,
|
||||||
|
.face = face,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deinit(self: *Face) void {
|
||||||
|
self.face.deinit();
|
||||||
|
self.* = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Change the size of the loaded font face. If you're using a texture
|
||||||
|
/// atlas, you should invalidate all the previous values if cached.
|
||||||
|
pub fn setSize(self: Face, size: DesiredSize) !void {
|
||||||
|
return try setSize_(self.face, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setSize_(face: freetype.Face, size: DesiredSize) !void {
|
||||||
// If we have fixed sizes, we just have to try to pick the one closest
|
// If we have fixed sizes, we just have to try to pick the one closest
|
||||||
// to what the user requested. Otherwise, we can choose an arbitrary
|
// to what the user requested. Otherwise, we can choose an arbitrary
|
||||||
// pixel size.
|
// pixel size.
|
||||||
@ -75,9 +76,6 @@ pub fn loadFaceFromMemory(
|
|||||||
const size_26dot6 = @intCast(i32, size.points << 6); // mult by 64
|
const size_26dot6 = @intCast(i32, size.points << 6); // mult by 64
|
||||||
try face.setCharSize(0, size_26dot6, size.xdpi, size.ydpi);
|
try face.setCharSize(0, size_26dot6, size.xdpi, size.ydpi);
|
||||||
} else try selectSizeNearest(face, size.pixels());
|
} else try selectSizeNearest(face, size.pixels());
|
||||||
|
|
||||||
// Success, persist
|
|
||||||
self.face = face;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Selects the fixed size in the loaded face that is closest to the
|
/// Selects the fixed size in the loaded face that is closest to the
|
||||||
@ -98,22 +96,26 @@ fn selectSizeNearest(face: freetype.Face, size: u32) !void {
|
|||||||
try face.selectSize(best_i);
|
try face.selectSize(best_i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the glyph index for the given Unicode code point. If this
|
||||||
|
/// face doesn't support this glyph, null is returned.
|
||||||
|
pub fn glyphIndex(self: Face, cp: u32) ?u32 {
|
||||||
|
return self.face.getCharIndex(cp);
|
||||||
|
}
|
||||||
|
|
||||||
/// Load a glyph for this face. The codepoint can be either a u8 or
|
/// Load a glyph for this face. The codepoint can be either a u8 or
|
||||||
/// []const u8 depending on if you know it is ASCII or must be UTF-8 decoded.
|
/// []const u8 depending on if you know it is ASCII or must be UTF-8 decoded.
|
||||||
pub fn loadGlyph(self: Face, alloc: Allocator, atlas: *Atlas, cp: u32) !Glyph {
|
pub fn loadGlyph(self: Face, alloc: Allocator, atlas: *Atlas, cp: u32) !Glyph {
|
||||||
const face = self.face.?;
|
|
||||||
|
|
||||||
// We need a UTF32 codepoint for freetype
|
// We need a UTF32 codepoint for freetype
|
||||||
const glyph_index = face.getCharIndex(cp) orelse return error.GlyphNotFound;
|
const glyph_index = self.glyphIndex(cp) orelse return error.GlyphNotFound;
|
||||||
//log.warn("glyph index: {}", .{glyph_index});
|
//log.warn("glyph index: {}", .{glyph_index});
|
||||||
|
|
||||||
// If our glyph has color, we want to render the color
|
// If our glyph has color, we want to render the color
|
||||||
try face.loadGlyph(glyph_index, .{
|
try self.face.loadGlyph(glyph_index, .{
|
||||||
.render = true,
|
.render = true,
|
||||||
.color = face.hasColor(),
|
.color = self.face.hasColor(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const glyph = face.handle.*.glyph;
|
const glyph = self.face.handle.*.glyph;
|
||||||
const bitmap = glyph.*.bitmap;
|
const bitmap = glyph.*.bitmap;
|
||||||
|
|
||||||
// Ensure we know how to work with the font format. And assure that
|
// Ensure we know how to work with the font format. And assure that
|
||||||
@ -182,7 +184,7 @@ pub fn loadGlyph(self: Face, alloc: Allocator, atlas: *Atlas, cp: u32) !Glyph {
|
|||||||
pub fn unitsToPxY(self: Face, units: i32) i32 {
|
pub fn unitsToPxY(self: Face, units: i32) i32 {
|
||||||
return @intCast(i32, freetype.mulFix(
|
return @intCast(i32, freetype.mulFix(
|
||||||
units,
|
units,
|
||||||
@intCast(i32, self.face.?.handle.*.size.*.metrics.y_scale),
|
@intCast(i32, self.face.handle.*.size.*.metrics.y_scale),
|
||||||
) >> 6);
|
) >> 6);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -201,11 +203,9 @@ test {
|
|||||||
var atlas = try Atlas.init(alloc, 512, .greyscale);
|
var atlas = try Atlas.init(alloc, 512, .greyscale);
|
||||||
defer atlas.deinit(alloc);
|
defer atlas.deinit(alloc);
|
||||||
|
|
||||||
var font = try init(lib);
|
var font = try init(lib, testFont, .{ .points = 12 });
|
||||||
defer font.deinit();
|
defer font.deinit();
|
||||||
|
|
||||||
try font.loadFaceFromMemory(testFont, .{ .points = 12 });
|
|
||||||
|
|
||||||
// Generate all visible ASCII
|
// Generate all visible ASCII
|
||||||
var i: u8 = 32;
|
var i: u8 = 32;
|
||||||
while (i < 127) : (i += 1) {
|
while (i < 127) : (i += 1) {
|
||||||
@ -223,9 +223,8 @@ test "color emoji" {
|
|||||||
var atlas = try Atlas.init(alloc, 512, .rgba);
|
var atlas = try Atlas.init(alloc, 512, .rgba);
|
||||||
defer atlas.deinit(alloc);
|
defer atlas.deinit(alloc);
|
||||||
|
|
||||||
var font = try init(lib);
|
var font = try init(lib, testFont, .{ .points = 12 });
|
||||||
defer font.deinit();
|
defer font.deinit();
|
||||||
|
|
||||||
try font.loadFaceFromMemory(testFont, .{ .points = 12 });
|
|
||||||
_ = try font.loadGlyph(alloc, &atlas, '🥸');
|
_ = try font.loadGlyph(alloc, &atlas, '🥸');
|
||||||
}
|
}
|
||||||
|
@ -61,9 +61,8 @@ pub fn loadFaceFromMemory(
|
|||||||
source: [:0]const u8,
|
source: [:0]const u8,
|
||||||
size: Face.DesiredSize,
|
size: Face.DesiredSize,
|
||||||
) !void {
|
) !void {
|
||||||
var face = try Face.init(self.lib);
|
var face = try Face.init(self.lib, source, size);
|
||||||
errdefer face.deinit();
|
errdefer face.deinit();
|
||||||
try face.loadFaceFromMemory(source, size);
|
|
||||||
|
|
||||||
@field(self, switch (style) {
|
@field(self, switch (style) {
|
||||||
.regular => "regular",
|
.regular => "regular",
|
||||||
|
Reference in New Issue
Block a user