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;
void* userdata;
double scale_factor;
uint8_t font_size;
float font_size;
const char* working_directory;
const char* command;
} ghostty_surface_config_s;

View File

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

View File

@ -41,7 +41,11 @@ pub fn build(b: *std.Build) !void {
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"));
module.addIncludePath(freetype_dep.builder.dependency("freetype", .{}).path("include"));

View File

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

View File

@ -314,7 +314,7 @@ pub const Surface = struct {
scale_factor: f64 = 1,
/// 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.
working_directory: [*:0]const u8 = "",
@ -1049,7 +1049,7 @@ pub const Surface = struct {
}
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;
break :font_size self.core_surface.font_size.points;
};

View File

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

View File

@ -99,8 +99,12 @@ const c = @cImport({
/// separate repetitive entries in your config).
@"font-feature": RepeatableString = .{},
/// Font size in points
@"font-size": u8 = switch (builtin.os.tag) {
/// Font size in points. This value can be a non-integer and the nearest integer
/// 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
// is purely subjective but this is easy to modify.
.macos => 13,

View File

@ -42,8 +42,8 @@ fn getValue(ptr_raw: *anyopaque, value: anytype) bool {
ptr.* = @intCast(value);
},
f32, f64 => {
const ptr: *f64 = @ptrCast(@alignCast(ptr_raw));
f32, f64 => |Float| {
const ptr: *Float = @ptrCast(@alignCast(ptr_raw));
ptr.* = @floatCast(value);
},
@ -102,9 +102,9 @@ test "u8" {
defer c.deinit();
c.@"font-size" = 24;
var cval: c_uint = undefined;
var cval: f32 = undefined;
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" {

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| {
log.warn("error loading deferred face err={}", .{err});
return;

View File

@ -575,7 +575,9 @@ pub const Key = struct {
/// Hash the key with the given hasher.
pub fn hash(self: Key, hasher: anytype) void {
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);
for (self.descriptors) |d| d.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
/// to pixels, we will use 72 DPI for Mac and 96 DPI for everything else.
/// (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
/// specific styles.
@ -69,7 +69,7 @@ pub const Descriptor = struct {
autoHashStrat(hasher, self.family, .Deep);
autoHashStrat(hasher, self.style, .Deep);
autoHash(hasher, self.codepoint);
autoHash(hasher, self.size);
autoHash(hasher, @as(u32, @bitCast(self.size)));
autoHash(hasher, self.bold);
autoHash(hasher, self.italic);
autoHash(hasher, self.monospace);
@ -125,7 +125,7 @@ pub const Descriptor = struct {
}
if (self.size > 0) assert(pat.add(
.size,
.{ .integer = self.size },
.{ .integer = @intFromFloat(@round(self.size)) },
false,
));
if (self.bold) assert(pat.add(
@ -183,7 +183,7 @@ pub const Descriptor = struct {
// Set our size attribute if set
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(
.sint32,
&size32,

View File

@ -35,7 +35,7 @@ pub const Options = struct {
/// The desired size for loading a font.
pub const DesiredSize = struct {
// Desired size in points
points: u8,
points: f32,
// The DPI of the screen so we can convert points to pixels.
xdpi: u16 = default_dpi,
@ -44,8 +44,7 @@ pub const DesiredSize = struct {
// Converts points to pixels
pub fn pixels(self: DesiredSize) u16 {
// 1 point = 1/72 inch
const points_u16: u16 = @intCast(self.points);
return (points_u16 * self.ydpi) / 72;
return @intFromFloat(@round((self.points * @as(f32, @floatFromInt(self.ydpi))) / 72));
}
};

View File

@ -137,7 +137,7 @@ pub const Face = struct {
// to what the user requested. Otherwise, we can choose an arbitrary
// pixel size.
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);
} 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;
}
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(
alloc,
ptr[0..len],

View File

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