mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-15 16:26:08 +03:00
Merge pull request #1734 from mitchellh/ct-fallback
coretext: let macOS choose the font for CJK Unified Ideographs
This commit is contained in:
@ -18,6 +18,18 @@ pub const Font = opaque {
|
||||
) orelse Allocator.Error.OutOfMemory;
|
||||
}
|
||||
|
||||
pub fn createForString(
|
||||
self: *Font,
|
||||
str: *foundation.String,
|
||||
range: foundation.Range,
|
||||
) ?*Font {
|
||||
return @ptrCast(@constCast(c.CTFontCreateForString(
|
||||
@ptrCast(self),
|
||||
@ptrCast(str),
|
||||
@bitCast(range),
|
||||
)));
|
||||
}
|
||||
|
||||
pub fn copyWithAttributes(
|
||||
self: *Font,
|
||||
size: f32,
|
||||
@ -51,6 +63,10 @@ pub const Font = opaque {
|
||||
return @ptrCast(@constCast(c.CTFontCopyFeatures(@ptrCast(self))));
|
||||
}
|
||||
|
||||
pub fn copyDefaultCascadeListForLanguages(self: *Font) *foundation.Array {
|
||||
return @ptrCast(@constCast(c.CTFontCopyDefaultCascadeListForLanguages(@ptrCast(self), null)));
|
||||
}
|
||||
|
||||
pub fn getGlyphCount(self: *Font) usize {
|
||||
return @intCast(c.CTFontGetGlyphCount(@ptrCast(self)));
|
||||
}
|
||||
|
@ -172,7 +172,7 @@ pub fn getIndex(
|
||||
if (self.discover) |disco| discover: {
|
||||
const load_opts = self.collection.load_options orelse
|
||||
break :discover;
|
||||
var disco_it = disco.discover(alloc, .{
|
||||
var disco_it = disco.discoverFallback(alloc, &self.collection, .{
|
||||
.codepoint = cp,
|
||||
.size = load_opts.size.points,
|
||||
.bold = style == .bold or style == .bold_italic,
|
||||
|
@ -5,6 +5,7 @@ const assert = std.debug.assert;
|
||||
const fontconfig = @import("fontconfig");
|
||||
const macos = @import("macos");
|
||||
const options = @import("main.zig").options;
|
||||
const Collection = @import("main.zig").Collection;
|
||||
const DeferredFace = @import("main.zig").DeferredFace;
|
||||
const Variation = @import("main.zig").face.Variation;
|
||||
|
||||
@ -258,7 +259,11 @@ pub const Fontconfig = struct {
|
||||
|
||||
/// Discover fonts from a descriptor. This returns an iterator that can
|
||||
/// be used to build up the deferred fonts.
|
||||
pub fn discover(self: *const Fontconfig, alloc: Allocator, desc: Descriptor) !DiscoverIterator {
|
||||
pub fn discover(
|
||||
self: *const Fontconfig,
|
||||
alloc: Allocator,
|
||||
desc: Descriptor,
|
||||
) !DiscoverIterator {
|
||||
_ = alloc;
|
||||
|
||||
// Build our pattern that we'll search for
|
||||
@ -282,6 +287,16 @@ pub const Fontconfig = struct {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn discoverFallback(
|
||||
self: *const Fontconfig,
|
||||
alloc: Allocator,
|
||||
collection: *Collection,
|
||||
desc: Descriptor,
|
||||
) !DiscoverIterator {
|
||||
_ = collection;
|
||||
return try self.discover(alloc, desc);
|
||||
}
|
||||
|
||||
pub const DiscoverIterator = struct {
|
||||
config: *fontconfig.Config,
|
||||
pattern: *fontconfig.Pattern,
|
||||
@ -364,6 +379,87 @@ pub const CoreText = struct {
|
||||
};
|
||||
}
|
||||
|
||||
pub fn discoverFallback(
|
||||
self: *const CoreText,
|
||||
alloc: Allocator,
|
||||
collection: *Collection,
|
||||
desc: Descriptor,
|
||||
) !DiscoverIterator {
|
||||
// If we have a codepoint within the CJK unified ideographs block
|
||||
// then we fallback to macOS to find a font that supports it because
|
||||
// there isn't a better way manually with CoreText that I can find that
|
||||
// properly takes into account system locale.
|
||||
//
|
||||
// References:
|
||||
// - http://unicode.org/charts/PDF/U4E00.pdf
|
||||
// - https://chromium.googlesource.com/chromium/src/+/main/third_party/blink/renderer/platform/fonts/LocaleInFonts.md#unified-han-ideographs
|
||||
if (desc.codepoint >= 0x4E00 and
|
||||
desc.codepoint <= 0x9FFF)
|
||||
han: {
|
||||
const han = try self.discoverCodepoint(
|
||||
collection,
|
||||
desc,
|
||||
) orelse break :han;
|
||||
|
||||
// This is silly but our discover iterator needs a slice so
|
||||
// we allocate here. This isn't a performance bottleneck but
|
||||
// this is something we can optimize very easily...
|
||||
const list = try alloc.alloc(*macos.text.FontDescriptor, 1);
|
||||
errdefer alloc.free(list);
|
||||
list[0] = han;
|
||||
|
||||
return DiscoverIterator{
|
||||
.alloc = alloc,
|
||||
.list = list,
|
||||
.i = 0,
|
||||
};
|
||||
}
|
||||
|
||||
return try self.discover(alloc, desc);
|
||||
}
|
||||
|
||||
/// Discover a font for a specific codepoint using the CoreText
|
||||
/// CTFontCreateForString API.
|
||||
fn discoverCodepoint(
|
||||
self: *const CoreText,
|
||||
collection: *Collection,
|
||||
desc: Descriptor,
|
||||
) !?*macos.text.FontDescriptor {
|
||||
_ = self;
|
||||
|
||||
assert(desc.codepoint > 0);
|
||||
|
||||
// Get our original font. This is dependent on the requestd style
|
||||
// from the descriptor.
|
||||
const original = original: {
|
||||
break :original try collection.getFace(.{ .style = .regular });
|
||||
};
|
||||
|
||||
// We need it in utf8 format
|
||||
var buf: [4]u8 = undefined;
|
||||
const len = try std.unicode.utf8Encode(
|
||||
@intCast(desc.codepoint),
|
||||
&buf,
|
||||
);
|
||||
|
||||
// We need a CFString
|
||||
const str = try macos.foundation.String.createWithBytes(
|
||||
buf[0..len],
|
||||
.utf8,
|
||||
false,
|
||||
);
|
||||
defer str.release();
|
||||
|
||||
// Get our font
|
||||
const font = original.font.createForString(
|
||||
str,
|
||||
macos.foundation.Range.init(0, 1),
|
||||
) orelse return null;
|
||||
defer font.release();
|
||||
|
||||
// Get the descriptor
|
||||
return font.copyDescriptor();
|
||||
}
|
||||
fn copyMatchingDescriptors(
|
||||
alloc: Allocator,
|
||||
list: *macos.foundation.Array,
|
||||
|
Reference in New Issue
Block a user