mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 00:36:07 +03:00
font size is now in font points, determine size based on window DPI
This commit is contained in:
12
src/Grid.zig
12
src/Grid.zig
@ -11,7 +11,6 @@ const terminal = @import("terminal/main.zig");
|
||||
const Terminal = terminal.Terminal;
|
||||
const gl = @import("opengl.zig");
|
||||
const trace = @import("tracy").trace;
|
||||
const Config = @import("config.zig").Config;
|
||||
const math = @import("math.zig");
|
||||
|
||||
const log = std.log.scoped(.grid);
|
||||
@ -134,7 +133,10 @@ const GPUCellMode = enum(u8) {
|
||||
}
|
||||
};
|
||||
|
||||
pub fn init(alloc: Allocator, config: *const Config) !Grid {
|
||||
pub fn init(
|
||||
alloc: Allocator,
|
||||
font_size: font.Face.DesiredSize,
|
||||
) !Grid {
|
||||
// Initialize our font atlas. We will initially populate the
|
||||
// font atlas with all the visible ASCII characters since they are common.
|
||||
var atlas = try Atlas.init(alloc, 512, .greyscale);
|
||||
@ -153,8 +155,8 @@ pub fn init(alloc: Allocator, config: *const Config) !Grid {
|
||||
font_set.families.appendAssumeCapacity(fam: {
|
||||
var fam = try font.Family.init(atlas);
|
||||
errdefer fam.deinit(alloc);
|
||||
try fam.loadFaceFromMemory(.regular, face_ttf, config.@"font-size");
|
||||
try fam.loadFaceFromMemory(.bold, face_bold_ttf, config.@"font-size");
|
||||
try fam.loadFaceFromMemory(.regular, face_ttf, font_size);
|
||||
try fam.loadFaceFromMemory(.bold, face_bold_ttf, font_size);
|
||||
break :fam fam;
|
||||
});
|
||||
|
||||
@ -162,7 +164,7 @@ pub fn init(alloc: Allocator, config: *const Config) !Grid {
|
||||
font_set.families.appendAssumeCapacity(fam: {
|
||||
var fam_emoji = try font.Family.init(atlas_color);
|
||||
errdefer fam_emoji.deinit(alloc);
|
||||
try fam_emoji.loadFaceFromMemory(.regular, face_emoji_ttf, config.@"font-size");
|
||||
try fam_emoji.loadFaceFromMemory(.regular, face_emoji_ttf, font_size);
|
||||
break :fam fam_emoji;
|
||||
});
|
||||
|
||||
|
@ -14,6 +14,7 @@ const glfw = @import("glfw");
|
||||
const gl = @import("opengl.zig");
|
||||
const libuv = @import("libuv");
|
||||
const Pty = @import("Pty.zig");
|
||||
const font = @import("font/main.zig");
|
||||
const Command = @import("Command.zig");
|
||||
const SegmentedPool = @import("segmented_pool.zig").SegmentedPool;
|
||||
const trace = @import("tracy").trace;
|
||||
@ -192,6 +193,18 @@ pub fn create(alloc: Allocator, loop: libuv.Loop, config: *const Config) !*Windo
|
||||
}
|
||||
}
|
||||
|
||||
// Determine our DPI configurations so we can properly configure
|
||||
// font points to pixels and handle other high-DPI scaling factors.
|
||||
const content_scale = try window.getContentScale();
|
||||
const x_dpi = content_scale.x_scale * font.Face.default_dpi;
|
||||
const y_dpi = content_scale.y_scale * font.Face.default_dpi;
|
||||
log.debug("xscale={} yscale={} xdpi={} ydpi={}", .{
|
||||
content_scale.x_scale,
|
||||
content_scale.y_scale,
|
||||
x_dpi,
|
||||
y_dpi,
|
||||
});
|
||||
|
||||
// Culling, probably not necessary. We have to change the winding
|
||||
// order since our 0,0 is top-left.
|
||||
gl.c.glEnable(gl.c.GL_CULL_FACE);
|
||||
@ -203,7 +216,11 @@ pub fn create(alloc: Allocator, loop: libuv.Loop, config: *const Config) !*Windo
|
||||
|
||||
// Create our terminal grid with the initial window size
|
||||
const window_size = try window.getSize();
|
||||
var grid = try Grid.init(alloc, config);
|
||||
var grid = try Grid.init(alloc, .{
|
||||
.points = config.@"font-size",
|
||||
.xdpi = @floatToInt(u32, x_dpi),
|
||||
.ydpi = @floatToInt(u32, y_dpi),
|
||||
});
|
||||
try grid.setScreenSize(.{ .width = window_size.width, .height = window_size.height });
|
||||
grid.background = .{
|
||||
.r = config.background.r,
|
||||
|
@ -6,11 +6,8 @@ const inputpkg = @import("input.zig");
|
||||
/// Config is the main config struct. These fields map directly to the
|
||||
/// CLI flag names hence we use a lot of `@""` syntax to support hyphens.
|
||||
pub const Config = struct {
|
||||
/// Font size
|
||||
/// TODO: this default size is too big, what we need to do is use a reasonable
|
||||
/// size and then mult a high-DPI scaling factor. This is only high because
|
||||
/// all our test machines are high-DPI right now.
|
||||
@"font-size": u8 = 32,
|
||||
/// Font size in points
|
||||
@"font-size": u8 = 12,
|
||||
|
||||
/// Background color for the window.
|
||||
background: Color = .{ .r = 0, .g = 0, .b = 0 },
|
||||
|
@ -6,6 +6,7 @@
|
||||
const Face = @This();
|
||||
|
||||
const std = @import("std");
|
||||
const builtin = @import("builtin");
|
||||
const assert = std.debug.assert;
|
||||
const testing = std.testing;
|
||||
const Allocator = std.mem.Allocator;
|
||||
@ -22,6 +23,11 @@ ft_library: ftc.FT_Library,
|
||||
/// Our font face.
|
||||
ft_face: ftc.FT_Face = null,
|
||||
|
||||
/// 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
|
||||
/// using whatever platform method you can.
|
||||
pub const default_dpi = if (builtin.os.tag == .macos) 72 else 96;
|
||||
|
||||
pub fn init(lib: ftc.FT_Library) !Face {
|
||||
return Face{
|
||||
.ft_library = lib,
|
||||
@ -37,10 +43,28 @@ pub fn deinit(self: *Face) void {
|
||||
self.* = undefined;
|
||||
}
|
||||
|
||||
/// Loads a font to use.
|
||||
///
|
||||
/// This can only be called if a font is not already loaded.
|
||||
pub fn loadFaceFromMemory(self: *Face, source: [:0]const u8, size: u32) !void {
|
||||
/// The desired size for loading a font.
|
||||
pub const DesiredSize = struct {
|
||||
// Desired size in points
|
||||
points: u32,
|
||||
|
||||
// The DPI of the screen so we can convert points to pixels.
|
||||
xdpi: u32 = default_dpi,
|
||||
ydpi: u32 = default_dpi,
|
||||
|
||||
// Converts points to pixels
|
||||
pub fn pixels(self: DesiredSize) u32 {
|
||||
// 1 point = 1/72 inch
|
||||
return (self.points * self.ydpi) / 72;
|
||||
}
|
||||
};
|
||||
|
||||
/// Loads a font to use. This can only be called if a font is not already loaded.
|
||||
pub fn loadFaceFromMemory(
|
||||
self: *Face,
|
||||
source: [:0]const u8,
|
||||
size: DesiredSize,
|
||||
) !void {
|
||||
assert(self.ft_face == null);
|
||||
|
||||
if (ftc.FT_New_Memory_Face(
|
||||
@ -62,9 +86,10 @@ pub fn loadFaceFromMemory(self: *Face, source: [:0]const u8, size: u32) !void {
|
||||
// to what the user requested. Otherwise, we can choose an arbitrary
|
||||
// pixel size.
|
||||
if (!ftc.FT_HAS_FIXED_SIZES(self.ft_face)) {
|
||||
if (ftc.FT_Set_Pixel_Sizes(self.ft_face, size, size) != ftok)
|
||||
const size_26dot6 = size.points << 6; // mult by 64
|
||||
if (ftc.FT_Set_Char_Size(self.ft_face, 0, size_26dot6, size.xdpi, size.ydpi) != ftok)
|
||||
return error.FaceLoadFailed;
|
||||
} else try self.selectSizeNearest(size);
|
||||
} else try self.selectSizeNearest(size.pixels());
|
||||
}
|
||||
|
||||
/// Selects the fixed size in the loaded face that is closest to the
|
||||
@ -202,7 +227,7 @@ test {
|
||||
var font = try init(ft_lib);
|
||||
defer font.deinit();
|
||||
|
||||
try font.loadFaceFromMemory(testFont, 48);
|
||||
try font.loadFaceFromMemory(testFont, .{ .points = 12 });
|
||||
|
||||
// Generate all visible ASCII
|
||||
var i: u8 = 32;
|
||||
@ -226,6 +251,6 @@ test "color emoji" {
|
||||
var font = try init(ft_lib);
|
||||
defer font.deinit();
|
||||
|
||||
try font.loadFaceFromMemory(testFont, 48);
|
||||
try font.loadFaceFromMemory(testFont, .{ .points = 12 });
|
||||
_ = try font.loadGlyph(alloc, &atlas, '🥸');
|
||||
}
|
||||
|
@ -128,12 +128,12 @@ test {
|
||||
var set: FallbackSet = .{};
|
||||
try set.families.append(alloc, fam: {
|
||||
var fam = try Family.init(try Atlas.init(alloc, 512, .greyscale));
|
||||
try fam.loadFaceFromMemory(.regular, fontRegular, 48);
|
||||
try fam.loadFaceFromMemory(.regular, fontRegular, .{ .points = 48 });
|
||||
break :fam fam;
|
||||
});
|
||||
try set.families.append(alloc, fam: {
|
||||
var fam = try Family.init(try Atlas.init(alloc, 512, .rgba));
|
||||
try fam.loadFaceFromMemory(.regular, fontEmoji, 48);
|
||||
try fam.loadFaceFromMemory(.regular, fontEmoji, .{ .points = 48 });
|
||||
break :fam fam;
|
||||
});
|
||||
|
||||
|
@ -72,7 +72,7 @@ pub fn loadFaceFromMemory(
|
||||
self: *Family,
|
||||
comptime style: Style,
|
||||
source: [:0]const u8,
|
||||
size: u32,
|
||||
size: Face.DesiredSize,
|
||||
) !void {
|
||||
var face = try Face.init(self.ft_library);
|
||||
errdefer face.deinit();
|
||||
@ -148,7 +148,7 @@ test {
|
||||
var fam = try init(try Atlas.init(alloc, 512, .greyscale));
|
||||
defer fam.deinit(alloc);
|
||||
defer fam.atlas.deinit(alloc);
|
||||
try fam.loadFaceFromMemory(.regular, testFont, 48);
|
||||
try fam.loadFaceFromMemory(.regular, testFont, .{ .points = 12 });
|
||||
|
||||
// Generate all visible ASCII
|
||||
var i: u8 = 32;
|
||||
|
Reference in New Issue
Block a user