mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-15 08:16:13 +03:00
Merge pull request #1741 from qwerasd205/non-integer-point-size
feat(font): Non-integer point sizes
This commit is contained in:
@ -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;
|
||||||
|
@ -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
|
||||||
|
@ -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"));
|
||||||
|
|
||||||
|
@ -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);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -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;
|
||||||
};
|
};
|
||||||
|
@ -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,
|
||||||
|
|
||||||
|
@ -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,
|
||||||
|
@ -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" {
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
@ -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,
|
||||||
|
@ -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;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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());
|
||||||
}
|
}
|
||||||
|
@ -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],
|
||||||
|
@ -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,
|
||||||
|
Reference in New Issue
Block a user