font size is now in font points, determine size based on window DPI

This commit is contained in:
Mitchell Hashimoto
2022-08-25 12:29:28 -07:00
parent 46bbab5d10
commit 9601920b4d
6 changed files with 64 additions and 23 deletions

View File

@ -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;
});

View File

@ -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,

View File

@ -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 },

View File

@ -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, '🥸');
}

View File

@ -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;
});

View File

@ -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;