mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 16:56:09 +03:00
font: move auto-italicization to Group
This commit is contained in:
@ -230,7 +230,7 @@ pub fn init(
|
|||||||
defer disco_it.deinit();
|
defer disco_it.deinit();
|
||||||
if (try disco_it.next()) |face| {
|
if (try disco_it.next()) |face| {
|
||||||
log.info("font regular: {s}", .{try face.name()});
|
log.info("font regular: {s}", .{try face.name()});
|
||||||
try group.addFace(alloc, .regular, face);
|
try group.addFace(.regular, face);
|
||||||
} else log.warn("font-family not found: {s}", .{family});
|
} else log.warn("font-family not found: {s}", .{family});
|
||||||
}
|
}
|
||||||
if (config.@"font-family-bold") |family| {
|
if (config.@"font-family-bold") |family| {
|
||||||
@ -242,7 +242,7 @@ pub fn init(
|
|||||||
defer disco_it.deinit();
|
defer disco_it.deinit();
|
||||||
if (try disco_it.next()) |face| {
|
if (try disco_it.next()) |face| {
|
||||||
log.info("font bold: {s}", .{try face.name()});
|
log.info("font bold: {s}", .{try face.name()});
|
||||||
try group.addFace(alloc, .bold, face);
|
try group.addFace(.bold, face);
|
||||||
} else log.warn("font-family-bold not found: {s}", .{family});
|
} else log.warn("font-family-bold not found: {s}", .{family});
|
||||||
}
|
}
|
||||||
if (config.@"font-family-italic") |family| {
|
if (config.@"font-family-italic") |family| {
|
||||||
@ -254,7 +254,7 @@ pub fn init(
|
|||||||
defer disco_it.deinit();
|
defer disco_it.deinit();
|
||||||
if (try disco_it.next()) |face| {
|
if (try disco_it.next()) |face| {
|
||||||
log.info("font italic: {s}", .{try face.name()});
|
log.info("font italic: {s}", .{try face.name()});
|
||||||
try group.addFace(alloc, .italic, face);
|
try group.addFace(.italic, face);
|
||||||
} else log.warn("font-family-italic not found: {s}", .{family});
|
} else log.warn("font-family-italic not found: {s}", .{family});
|
||||||
}
|
}
|
||||||
if (config.@"font-family-bold-italic") |family| {
|
if (config.@"font-family-bold-italic") |family| {
|
||||||
@ -267,53 +267,32 @@ pub fn init(
|
|||||||
defer disco_it.deinit();
|
defer disco_it.deinit();
|
||||||
if (try disco_it.next()) |face| {
|
if (try disco_it.next()) |face| {
|
||||||
log.info("font bold+italic: {s}", .{try face.name()});
|
log.info("font bold+italic: {s}", .{try face.name()});
|
||||||
try group.addFace(alloc, .bold_italic, face);
|
try group.addFace(.bold_italic, face);
|
||||||
} else log.warn("font-family-bold-italic not found: {s}", .{family});
|
} else log.warn("font-family-bold-italic not found: {s}", .{family});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Our built-in font will be used as a backup
|
// Our built-in font will be used as a backup
|
||||||
try group.addFace(
|
try group.addFace(
|
||||||
alloc,
|
|
||||||
.regular,
|
.regular,
|
||||||
font.DeferredFace.initLoaded(try font.Face.init(font_lib, face_ttf, font_size)),
|
font.DeferredFace.initLoaded(try font.Face.init(font_lib, face_ttf, font_size)),
|
||||||
);
|
);
|
||||||
try group.addFace(
|
try group.addFace(
|
||||||
alloc,
|
|
||||||
.bold,
|
.bold,
|
||||||
font.DeferredFace.initLoaded(try font.Face.init(font_lib, face_bold_ttf, font_size)),
|
font.DeferredFace.initLoaded(try font.Face.init(font_lib, face_bold_ttf, font_size)),
|
||||||
);
|
);
|
||||||
|
|
||||||
// If we support auto-italicization and we don't have an italic face,
|
// Auto-italicize if we have to.
|
||||||
// then we can try to auto-italicize our regular face.
|
try group.italicize();
|
||||||
if (comptime font.DeferredFace.canItalicize()) {
|
|
||||||
if (group.getFace(.italic) == null) {
|
|
||||||
if (group.getFace(.regular)) |regular| {
|
|
||||||
if (try regular.italicize()) |face| {
|
|
||||||
log.info("font auto-italicized: {s}", .{try face.name()});
|
|
||||||
try group.addFace(alloc, .italic, face);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// We don't support auto-italics. If we don't have an italic font
|
|
||||||
// face let the user know so they aren't surprised (if they look
|
|
||||||
// at logs).
|
|
||||||
if (group.getFace(.italic) == null) {
|
|
||||||
log.warn("no italic font face available, italics will not render", .{});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Emoji fallback. We don't include this on Mac since Mac is expected
|
// Emoji fallback. We don't include this on Mac since Mac is expected
|
||||||
// to always have the Apple Emoji available.
|
// to always have the Apple Emoji available.
|
||||||
if (builtin.os.tag != .macos or font.Discover == void) {
|
if (builtin.os.tag != .macos or font.Discover == void) {
|
||||||
try group.addFace(
|
try group.addFace(
|
||||||
alloc,
|
|
||||||
.regular,
|
.regular,
|
||||||
font.DeferredFace.initLoaded(try font.Face.init(font_lib, face_emoji_ttf, font_size)),
|
font.DeferredFace.initLoaded(try font.Face.init(font_lib, face_emoji_ttf, font_size)),
|
||||||
);
|
);
|
||||||
try group.addFace(
|
try group.addFace(
|
||||||
alloc,
|
|
||||||
.regular,
|
.regular,
|
||||||
font.DeferredFace.initLoaded(try font.Face.init(font_lib, face_emoji_text_ttf, font_size)),
|
font.DeferredFace.initLoaded(try font.Face.init(font_lib, face_emoji_text_ttf, font_size)),
|
||||||
);
|
);
|
||||||
@ -329,7 +308,7 @@ pub fn init(
|
|||||||
defer disco_it.deinit();
|
defer disco_it.deinit();
|
||||||
if (try disco_it.next()) |face| {
|
if (try disco_it.next()) |face| {
|
||||||
log.info("font emoji: {s}", .{try face.name()});
|
log.info("font emoji: {s}", .{try face.name()});
|
||||||
try group.addFace(alloc, .regular, face);
|
try group.addFace(.regular, face);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -72,13 +72,6 @@ pub const CoreText = struct {
|
|||||||
self.font.release();
|
self.font.release();
|
||||||
self.* = undefined;
|
self.* = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Auto-italicize the font by applying a skew.
|
|
||||||
pub fn italicize(self: *const CoreText) !CoreText {
|
|
||||||
const ct_font = try self.font.copyWithAttributes(0.0, &Face.italic_skew, null);
|
|
||||||
errdefer ct_font.release();
|
|
||||||
return .{ .font = ct_font };
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// WebCanvas specific data. This is only present when building with canvas.
|
/// WebCanvas specific data. This is only present when building with canvas.
|
||||||
@ -351,40 +344,6 @@ pub fn hasCodepoint(self: DeferredFace, cp: u32, p: ?Presentation) bool {
|
|||||||
unreachable;
|
unreachable;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if our deferred font implementation supports auto-itacilization.
|
|
||||||
pub fn canItalicize() bool {
|
|
||||||
return @hasDecl(FaceState, "italicize") and @hasDecl(Face, "italicize");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns a new deferred face with the italicized version of this face
|
|
||||||
/// by applying a skew. This is NOT TRUE italics. You should use the discovery
|
|
||||||
/// mechanism to try to find an italic font. This is a fallback for when
|
|
||||||
/// that fails.
|
|
||||||
pub fn italicize(self: *const DeferredFace) !?DeferredFace {
|
|
||||||
if (comptime !canItalicize()) return null;
|
|
||||||
|
|
||||||
var result: DeferredFace = .{};
|
|
||||||
|
|
||||||
if (self.face) |face| {
|
|
||||||
result.face = try face.italicize();
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (options.backend) {
|
|
||||||
.freetype => {},
|
|
||||||
.fontconfig_freetype => if (self.fc) |*fc| {
|
|
||||||
result.fc = try fc.italicize();
|
|
||||||
},
|
|
||||||
.coretext, .coretext_freetype => if (self.ct) |*ct| {
|
|
||||||
result.ct = try ct.italicize();
|
|
||||||
},
|
|
||||||
.web_canvas => if (self.wc) |*wc| {
|
|
||||||
result.wc = try wc.italicize();
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The wasm-compatible API.
|
/// The wasm-compatible API.
|
||||||
pub const Wasm = struct {
|
pub const Wasm = struct {
|
||||||
const wasm = @import("../os/wasm.zig");
|
const wasm = @import("../os/wasm.zig");
|
||||||
|
@ -98,22 +98,55 @@ pub fn deinit(self: *Group) void {
|
|||||||
///
|
///
|
||||||
/// The group takes ownership of the face. The face will be deallocated when
|
/// The group takes ownership of the face. The face will be deallocated when
|
||||||
/// the group is deallocated.
|
/// the group is deallocated.
|
||||||
pub fn addFace(self: *Group, alloc: Allocator, style: Style, face: DeferredFace) !void {
|
pub fn addFace(self: *Group, style: Style, face: DeferredFace) !void {
|
||||||
const list = self.faces.getPtr(style);
|
const list = self.faces.getPtr(style);
|
||||||
|
|
||||||
// We have some special indexes so we must never pass those.
|
// We have some special indexes so we must never pass those.
|
||||||
if (list.items.len >= FontIndex.Special.start - 1) return error.GroupFull;
|
if (list.items.len >= FontIndex.Special.start - 1) return error.GroupFull;
|
||||||
|
|
||||||
try list.append(alloc, .{ .deferred = face });
|
try list.append(self.alloc, .{ .deferred = face });
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the face for the given style. This will always return the first
|
/// Returns true if we have a face for the given style, though the face may
|
||||||
/// face (if it exists). The returned pointer is only valid as long as
|
/// not be loaded yet.
|
||||||
/// the faces do not change.
|
pub fn hasFaceForStyle(self: Group, style: Style) bool {
|
||||||
pub fn getFace(self: *Group, style: Style) ?*DeferredFace {
|
const list = self.faces.get(style);
|
||||||
const list = self.faces.getPtr(style);
|
return list.items.len > 0;
|
||||||
if (list.items.len == 0) return null;
|
}
|
||||||
return &list.items[0];
|
|
||||||
|
/// This will automatically create an italicized font from the regular
|
||||||
|
/// font face if we don't have any italicized fonts.
|
||||||
|
pub fn italicize(self: *Group) !void {
|
||||||
|
// If we have an italic font, do nothing.
|
||||||
|
const italic_list = self.faces.getPtr(.italic);
|
||||||
|
if (italic_list.items.len > 0) return;
|
||||||
|
|
||||||
|
// Not all font backends support auto-italicization.
|
||||||
|
if (comptime !@hasDecl(Face, "italicize")) {
|
||||||
|
log.warn("no italic font face available, italics will not render", .{});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Our regular font. If we have no regular font we also do nothing.
|
||||||
|
const regular = regular: {
|
||||||
|
const list = self.faces.get(.regular);
|
||||||
|
if (list.items.len == 0) return;
|
||||||
|
|
||||||
|
// The font must be loaded.
|
||||||
|
break :regular try self.faceFromIndex(.{
|
||||||
|
.style = .regular,
|
||||||
|
.idx = 0,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Try to italicize it.
|
||||||
|
const face = try regular.italicize();
|
||||||
|
try italic_list.append(self.alloc, .{ .loaded = face });
|
||||||
|
|
||||||
|
var buf: [128]u8 = undefined;
|
||||||
|
if (face.name(&buf)) |name| {
|
||||||
|
log.info("font auto-italicized: {s}", .{name});
|
||||||
|
} else |_| {}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Resize the fonts to the desired size.
|
/// Resize the fonts to the desired size.
|
||||||
@ -229,7 +262,7 @@ pub fn indexForCodepoint(
|
|||||||
cp,
|
cp,
|
||||||
face.name() catch "<error>",
|
face.name() catch "<error>",
|
||||||
});
|
});
|
||||||
self.addFace(self.alloc, style, face) catch break :discover;
|
self.addFace(style, face) catch break :discover;
|
||||||
if (self.indexForCodepointExact(cp, style, p)) |value| return value;
|
if (self.indexForCodepointExact(cp, style, p)) |value| return value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -377,7 +410,7 @@ pub const Wasm = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export fn group_add_face(self: *Group, style: u16, face: *font.DeferredFace) void {
|
export fn group_add_face(self: *Group, style: u16, face: *font.DeferredFace) void {
|
||||||
return self.addFace(alloc, @enumFromInt(style), face.*) catch |err| {
|
return self.addFace(@enumFromInt(style), face.*) catch |err| {
|
||||||
log.warn("error adding face to group err={}", .{err});
|
log.warn("error adding face to group err={}", .{err});
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
@ -450,13 +483,13 @@ test {
|
|||||||
var group = try init(alloc, lib, .{ .points = 12 });
|
var group = try init(alloc, lib, .{ .points = 12 });
|
||||||
defer group.deinit();
|
defer group.deinit();
|
||||||
|
|
||||||
try group.addFace(alloc, .regular, DeferredFace.initLoaded(try Face.init(lib, testFont, .{ .points = 12 })));
|
try group.addFace(.regular, DeferredFace.initLoaded(try Face.init(lib, testFont, .{ .points = 12 })));
|
||||||
|
|
||||||
if (font.options.backend != .coretext) {
|
if (font.options.backend != .coretext) {
|
||||||
// Coretext doesn't support Noto's format
|
// Coretext doesn't support Noto's format
|
||||||
try group.addFace(alloc, .regular, DeferredFace.initLoaded(try Face.init(lib, testEmoji, .{ .points = 12 })));
|
try group.addFace(.regular, DeferredFace.initLoaded(try Face.init(lib, testEmoji, .{ .points = 12 })));
|
||||||
}
|
}
|
||||||
try group.addFace(alloc, .regular, DeferredFace.initLoaded(try Face.init(lib, testEmojiText, .{ .points = 12 })));
|
try group.addFace(.regular, DeferredFace.initLoaded(try Face.init(lib, testEmojiText, .{ .points = 12 })));
|
||||||
|
|
||||||
// Should find all visible ASCII
|
// Should find all visible ASCII
|
||||||
var i: u32 = 32;
|
var i: u32 = 32;
|
||||||
@ -549,7 +582,7 @@ test "resize" {
|
|||||||
var group = try init(alloc, lib, .{ .points = 12, .xdpi = 96, .ydpi = 96 });
|
var group = try init(alloc, lib, .{ .points = 12, .xdpi = 96, .ydpi = 96 });
|
||||||
defer group.deinit();
|
defer group.deinit();
|
||||||
|
|
||||||
try group.addFace(alloc, .regular, DeferredFace.initLoaded(try Face.init(lib, testFont, .{ .points = 12, .xdpi = 96, .ydpi = 96 })));
|
try group.addFace(.regular, DeferredFace.initLoaded(try Face.init(lib, testFont, .{ .points = 12, .xdpi = 96, .ydpi = 96 })));
|
||||||
|
|
||||||
// Load a letter
|
// Load a letter
|
||||||
{
|
{
|
||||||
@ -602,7 +635,7 @@ test "discover monospace with fontconfig and freetype" {
|
|||||||
defer lib.deinit();
|
defer lib.deinit();
|
||||||
var group = try init(alloc, lib, .{ .points = 12 });
|
var group = try init(alloc, lib, .{ .points = 12 });
|
||||||
defer group.deinit();
|
defer group.deinit();
|
||||||
try group.addFace(alloc, .regular, (try it.next()).?);
|
try group.addFace(.regular, (try it.next()).?);
|
||||||
|
|
||||||
// Should find all visible ASCII
|
// Should find all visible ASCII
|
||||||
var atlas_greyscale = try font.Atlas.init(alloc, 512, .greyscale);
|
var atlas_greyscale = try font.Atlas.init(alloc, 512, .greyscale);
|
||||||
@ -640,7 +673,7 @@ test "faceFromIndex returns pointer" {
|
|||||||
var group = try init(alloc, lib, .{ .points = 12, .xdpi = 96, .ydpi = 96 });
|
var group = try init(alloc, lib, .{ .points = 12, .xdpi = 96, .ydpi = 96 });
|
||||||
defer group.deinit();
|
defer group.deinit();
|
||||||
|
|
||||||
try group.addFace(alloc, .regular, DeferredFace.initLoaded(try Face.init(lib, testFont, .{ .points = 12, .xdpi = 96, .ydpi = 96 })));
|
try group.addFace(.regular, DeferredFace.initLoaded(try Face.init(lib, testFont, .{ .points = 12, .xdpi = 96, .ydpi = 96 })));
|
||||||
|
|
||||||
{
|
{
|
||||||
const idx = group.indexForCodepoint('A', .regular, null).?;
|
const idx = group.indexForCodepoint('A', .regular, null).?;
|
||||||
|
@ -183,7 +183,6 @@ test {
|
|||||||
|
|
||||||
// Setup group
|
// Setup group
|
||||||
try cache.group.addFace(
|
try cache.group.addFace(
|
||||||
alloc,
|
|
||||||
.regular,
|
.regular,
|
||||||
DeferredFace.initLoaded(try Face.init(lib, testFont, .{ .points = 12 })),
|
DeferredFace.initLoaded(try Face.init(lib, testFont, .{ .points = 12 })),
|
||||||
);
|
);
|
||||||
@ -340,7 +339,6 @@ test "resize" {
|
|||||||
|
|
||||||
// Setup group
|
// Setup group
|
||||||
try cache.group.addFace(
|
try cache.group.addFace(
|
||||||
alloc,
|
|
||||||
.regular,
|
.regular,
|
||||||
DeferredFace.initLoaded(try Face.init(lib, testFont, .{ .points = 12, .xdpi = 96, .ydpi = 96 })),
|
DeferredFace.initLoaded(try Face.init(lib, testFont, .{ .points = 12, .xdpi = 96, .ydpi = 96 })),
|
||||||
);
|
);
|
||||||
|
@ -795,12 +795,12 @@ fn testShaper(alloc: Allocator) !TestShaper {
|
|||||||
errdefer cache_ptr.*.deinit(alloc);
|
errdefer cache_ptr.*.deinit(alloc);
|
||||||
|
|
||||||
// Setup group
|
// Setup group
|
||||||
try cache_ptr.group.addFace(alloc, .regular, DeferredFace.initLoaded(try Face.init(lib, testFont, .{ .points = 12 })));
|
try cache_ptr.group.addFace(.regular, DeferredFace.initLoaded(try Face.init(lib, testFont, .{ .points = 12 })));
|
||||||
if (font.options.backend != .coretext) {
|
if (font.options.backend != .coretext) {
|
||||||
// Coretext doesn't support Noto's format
|
// Coretext doesn't support Noto's format
|
||||||
try cache_ptr.group.addFace(alloc, .regular, DeferredFace.initLoaded(try Face.init(lib, testEmoji, .{ .points = 12 })));
|
try cache_ptr.group.addFace(.regular, DeferredFace.initLoaded(try Face.init(lib, testEmoji, .{ .points = 12 })));
|
||||||
}
|
}
|
||||||
try cache_ptr.group.addFace(alloc, .regular, DeferredFace.initLoaded(try Face.init(lib, testEmojiText, .{ .points = 12 })));
|
try cache_ptr.group.addFace(.regular, DeferredFace.initLoaded(try Face.init(lib, testEmojiText, .{ .points = 12 })));
|
||||||
|
|
||||||
var cell_buf = try alloc.alloc(font.shape.Cell, 80);
|
var cell_buf = try alloc.alloc(font.shape.Cell, 80);
|
||||||
errdefer alloc.free(cell_buf);
|
errdefer alloc.free(cell_buf);
|
||||||
|
Reference in New Issue
Block a user