feat(font): Non-integer point sizes

Allows for high dpi displays to get odd numbered pixel sizes, for
example, 13.5pt @ 2px/pt for 27px font. This implementation performs
all the sizing calculations with f32, rounding to the nearest pixel
size when it comes to rendering. In the future this can be enhanced
by adding fractional scaling to support fractional pixel sizes.
This commit is contained in:
Qwerasd
2024-05-08 14:23:20 -04:00
parent 08940940d5
commit d4a7549222
7 changed files with 30 additions and 23 deletions

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,
@ -321,8 +321,8 @@ pub fn init(
// The font size we desire along with the DPI determined for the surface
const font_size: font.face.DesiredSize = .{
.points = config.@"font-size",
.xdpi = @intFromFloat(x_dpi),
.ydpi = @intFromFloat(y_dpi),
.xdpi = x_dpi,
.ydpi = y_dpi,
};
// Setup our font group. This will reuse an existing font group if
@ -1703,8 +1703,8 @@ pub fn contentScaleCallback(self: *Surface, content_scale: apprt.ContentScale) !
// Update our font size which is dependent on the DPI
const size = size: {
var size = self.font_size;
size.xdpi = @intFromFloat(x_dpi);
size.ydpi = @intFromFloat(y_dpi);
size.xdpi = x_dpi;
size.ydpi = y_dpi;
break :size size;
};
@ -3011,7 +3011,7 @@ pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !bool
log.debug("increase font size={}", .{delta});
var size = self.font_size;
size.points +|= delta;
size.points = size.points + delta;
try self.setFontSize(size);
},
@ -3019,7 +3019,7 @@ pub fn performBindingAction(self: *Surface, action: input.Binding.Action) !bool
log.debug("decrease font size={}", .{delta});
var size = self.font_size;
size.points = @max(1, size.points -| delta);
size.points = @max(1, size.points - delta);
try self.setFontSize(size);
},

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

@ -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, @as(u32, @bitCast(self.font_size.xdpi)));
autoHash(hasher, @as(u32, @bitCast(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 = @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,17 +35,16 @@ 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,
ydpi: u16 = default_dpi,
xdpi: f32 = default_dpi,
ydpi: f32 = default_dpi,
// 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 * self.ydpi) / 72));
}
};

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,