Merge pull request #1741 from qwerasd205/non-integer-point-size

feat(font): Non-integer point sizes
This commit is contained in:
Mitchell Hashimoto
2024-05-08 21:36:48 -07:00
committed by GitHub
15 changed files with 49 additions and 31 deletions

View File

@ -379,7 +379,7 @@ typedef struct {
ghostty_platform_u platform; ghostty_platform_u platform;
void* userdata; void* userdata;
double scale_factor; double scale_factor;
uint8_t font_size; float font_size;
const char* working_directory; const char* working_directory;
const char* command; const char* command;
} ghostty_surface_config_s; } ghostty_surface_config_s;

View File

@ -252,7 +252,7 @@ extension Ghostty {
/// libghostty, usually from the Ghostty configuration. /// libghostty, usually from the Ghostty configuration.
struct SurfaceConfiguration { struct SurfaceConfiguration {
/// Explicit font size to use in points /// Explicit font size to use in points
var fontSize: UInt8? = nil var fontSize: Float32? = nil
/// Explicit working directory to set /// Explicit working directory to set
var workingDirectory: String? = nil var workingDirectory: String? = nil

View File

@ -41,7 +41,11 @@ pub fn build(b: *std.Build) !void {
try apple_sdk.addPaths(b, module); try apple_sdk.addPaths(b, module);
} }
const freetype_dep = b.dependency("freetype", .{ .target = target, .optimize = optimize }); const freetype_dep = b.dependency("freetype", .{
.target = target,
.optimize = optimize,
.@"enable-libpng" = true,
});
lib.linkLibrary(freetype_dep.artifact("freetype")); lib.linkLibrary(freetype_dep.artifact("freetype"));
module.addIncludePath(freetype_dep.builder.dependency("freetype", .{}).path("include")); module.addIncludePath(freetype_dep.builder.dependency("freetype", .{}).path("include"));

View File

@ -194,7 +194,7 @@ const DerivedConfig = struct {
arena: ArenaAllocator, arena: ArenaAllocator,
/// For docs for these, see the associated config they are derived from. /// For docs for these, see the associated config they are derived from.
original_font_size: u8, original_font_size: f32,
keybind: configpkg.Keybinds, keybind: configpkg.Keybinds,
clipboard_read: configpkg.ClipboardAccess, clipboard_read: configpkg.ClipboardAccess,
clipboard_write: configpkg.ClipboardAccess, clipboard_write: configpkg.ClipboardAccess,
@ -3008,18 +3008,25 @@ pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !bool
), ),
.increase_font_size => |delta| { .increase_font_size => |delta| {
log.debug("increase font size={}", .{delta}); // Max delta is somewhat arbitrary.
const clamped_delta = @max(0, @min(255, delta));
log.debug("increase font size={}", .{clamped_delta});
var size = self.font_size; var size = self.font_size;
size.points +|= delta; // Max point size is somewhat arbitrary.
size.points = @min(size.points + clamped_delta, 255);
try self.setFontSize(size); try self.setFontSize(size);
}, },
.decrease_font_size => |delta| { .decrease_font_size => |delta| {
log.debug("decrease font size={}", .{delta}); // Max delta is somewhat arbitrary.
const clamped_delta = @max(0, @min(255, delta));
log.debug("decrease font size={}", .{clamped_delta});
var size = self.font_size; var size = self.font_size;
size.points = @max(1, size.points -| delta); size.points = @max(1, size.points - clamped_delta);
try self.setFontSize(size); try self.setFontSize(size);
}, },

View File

@ -314,7 +314,7 @@ pub const Surface = struct {
scale_factor: f64 = 1, scale_factor: f64 = 1,
/// The font size to inherit. If 0, default font size will be used. /// The font size to inherit. If 0, default font size will be used.
font_size: u8 = 0, font_size: f32 = 0,
/// The working directory to load into. /// The working directory to load into.
working_directory: [*:0]const u8 = "", working_directory: [*:0]const u8 = "",
@ -1049,7 +1049,7 @@ pub const Surface = struct {
} }
fn newSurfaceOptions(self: *const Surface) apprt.Surface.Options { fn newSurfaceOptions(self: *const Surface) apprt.Surface.Options {
const font_size: u8 = font_size: { const font_size: f32 = font_size: {
if (!self.app.config.@"window-inherit-font-size") break :font_size 0; if (!self.app.config.@"window-inherit-font-size") break :font_size 0;
break :font_size self.core_surface.font_size.points; break :font_size self.core_surface.font_size.points;
}; };

View File

@ -250,8 +250,10 @@ fn parseIntoField(
0, 0,
) catch return error.InvalidValue, ) catch return error.InvalidValue,
f64 => std.fmt.parseFloat( f32,
f64, f64,
=> |Float| std.fmt.parseFloat(
Float,
value orelse return error.ValueRequired, value orelse return error.ValueRequired,
) catch return error.InvalidValue, ) catch return error.InvalidValue,

View File

@ -99,8 +99,12 @@ const c = @cImport({
/// separate repetitive entries in your config). /// separate repetitive entries in your config).
@"font-feature": RepeatableString = .{}, @"font-feature": RepeatableString = .{},
/// Font size in points /// Font size in points. This value can be a non-integer and the nearest integer
@"font-size": u8 = switch (builtin.os.tag) { /// pixel size will be selected. If you have a high dpi display where 1pt = 2px
/// then you can get an odd numbered pixel size by specifying a half point.
///
/// For example, 13.5pt @ 2px/pt = 27px
@"font-size": f32 = switch (builtin.os.tag) {
// On macOS we default a little bigger since this tends to look better. This // On macOS we default a little bigger since this tends to look better. This
// is purely subjective but this is easy to modify. // is purely subjective but this is easy to modify.
.macos => 13, .macos => 13,

View File

@ -42,8 +42,8 @@ fn getValue(ptr_raw: *anyopaque, value: anytype) bool {
ptr.* = @intCast(value); ptr.* = @intCast(value);
}, },
f32, f64 => { f32, f64 => |Float| {
const ptr: *f64 = @ptrCast(@alignCast(ptr_raw)); const ptr: *Float = @ptrCast(@alignCast(ptr_raw));
ptr.* = @floatCast(value); ptr.* = @floatCast(value);
}, },
@ -102,9 +102,9 @@ test "u8" {
defer c.deinit(); defer c.deinit();
c.@"font-size" = 24; c.@"font-size" = 24;
var cval: c_uint = undefined; var cval: f32 = undefined;
try testing.expect(get(&c, .@"font-size", &cval)); try testing.expect(get(&c, .@"font-size", &cval));
try testing.expectEqual(@as(c_uint, 24), cval); try testing.expectEqual(@as(f32, 24), cval);
} }
test "enum" { test "enum" {

View File

@ -371,7 +371,7 @@ pub const Wasm = struct {
} }
} }
export fn deferred_face_load(self: *DeferredFace, pts: u16) void { export fn deferred_face_load(self: *DeferredFace, pts: f32) void {
self.load(.{}, .{ .points = pts }) catch |err| { self.load(.{}, .{ .points = pts }) catch |err| {
log.warn("error loading deferred face err={}", .{err}); log.warn("error loading deferred face err={}", .{err});
return; return;

View File

@ -575,7 +575,9 @@ pub const Key = struct {
/// Hash the key with the given hasher. /// Hash the key with the given hasher.
pub fn hash(self: Key, hasher: anytype) void { pub fn hash(self: Key, hasher: anytype) void {
const autoHash = std.hash.autoHash; const autoHash = std.hash.autoHash;
autoHash(hasher, self.font_size); autoHash(hasher, @as(u32, @bitCast(self.font_size.points)));
autoHash(hasher, self.font_size.xdpi);
autoHash(hasher, self.font_size.ydpi);
autoHash(hasher, self.descriptors.len); autoHash(hasher, self.descriptors.len);
for (self.descriptors) |d| d.hash(hasher); for (self.descriptors) |d| d.hash(hasher);
self.codepoint_map.hash(hasher); self.codepoint_map.hash(hasher);

View File

@ -49,7 +49,7 @@ pub const Descriptor = struct {
/// Font size in points that the font should support. For conversion /// Font size in points that the font should support. For conversion
/// to pixels, we will use 72 DPI for Mac and 96 DPI for everything else. /// to pixels, we will use 72 DPI for Mac and 96 DPI for everything else.
/// (If pixel conversion is necessary, i.e. emoji fonts) /// (If pixel conversion is necessary, i.e. emoji fonts)
size: u16 = 0, size: f32 = 0,
/// True if we want to search specifically for a font that supports /// True if we want to search specifically for a font that supports
/// specific styles. /// specific styles.
@ -69,7 +69,7 @@ pub const Descriptor = struct {
autoHashStrat(hasher, self.family, .Deep); autoHashStrat(hasher, self.family, .Deep);
autoHashStrat(hasher, self.style, .Deep); autoHashStrat(hasher, self.style, .Deep);
autoHash(hasher, self.codepoint); autoHash(hasher, self.codepoint);
autoHash(hasher, self.size); autoHash(hasher, @as(u32, @bitCast(self.size)));
autoHash(hasher, self.bold); autoHash(hasher, self.bold);
autoHash(hasher, self.italic); autoHash(hasher, self.italic);
autoHash(hasher, self.monospace); autoHash(hasher, self.monospace);
@ -125,7 +125,7 @@ pub const Descriptor = struct {
} }
if (self.size > 0) assert(pat.add( if (self.size > 0) assert(pat.add(
.size, .size,
.{ .integer = self.size }, .{ .integer = @intFromFloat(@round(self.size)) },
false, false,
)); ));
if (self.bold) assert(pat.add( if (self.bold) assert(pat.add(
@ -183,7 +183,7 @@ pub const Descriptor = struct {
// Set our size attribute if set // Set our size attribute if set
if (self.size > 0) { if (self.size > 0) {
const size32 = @as(i32, @intCast(self.size)); const size32: i32 = @intFromFloat(@round(self.size));
const size = try macos.foundation.Number.create( const size = try macos.foundation.Number.create(
.sint32, .sint32,
&size32, &size32,

View File

@ -35,7 +35,7 @@ pub const Options = struct {
/// 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
points: u8, points: f32,
// The DPI of the screen so we can convert points to pixels. // The DPI of the screen so we can convert points to pixels.
xdpi: u16 = default_dpi, xdpi: u16 = default_dpi,
@ -44,8 +44,7 @@ pub const DesiredSize = struct {
// Converts points to pixels // Converts points to pixels
pub fn pixels(self: DesiredSize) u16 { pub fn pixels(self: DesiredSize) u16 {
// 1 point = 1/72 inch // 1 point = 1/72 inch
const points_u16: u16 = @intCast(self.points); return @intFromFloat(@round((self.points * @as(f32, @floatFromInt(self.ydpi))) / 72));
return (points_u16 * self.ydpi) / 72;
} }
}; };

View File

@ -137,7 +137,7 @@ pub const Face = struct {
// 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.
if (face.isScalable()) { if (face.isScalable()) {
const size_26dot6 = @as(i32, @intCast(size.points)) << 6; // mult by 64 const size_26dot6: i32 = @intFromFloat(@round(size.points * 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());
} }

View File

@ -497,7 +497,7 @@ pub const Wasm = struct {
return face_new_(ptr, len, pts, p) catch null; return face_new_(ptr, len, pts, p) catch null;
} }
fn face_new_(ptr: [*]const u8, len: usize, pts: u16, presentation: u16) !*Face { fn face_new_(ptr: [*]const u8, len: usize, pts: f32, presentation: u16) !*Face {
var face = try Face.initNamed( var face = try Face.initNamed(
alloc, alloc,
ptr[0..len], ptr[0..len],

View File

@ -158,8 +158,8 @@ pub const Action = union(enum) {
paste_from_selection: void, paste_from_selection: void,
/// Increase/decrease the font size by a certain amount. /// Increase/decrease the font size by a certain amount.
increase_font_size: u8, increase_font_size: f32,
decrease_font_size: u8, decrease_font_size: f32,
/// Reset the font size to the original configured size. /// Reset the font size to the original configured size.
reset_font_size: void, reset_font_size: void,