Skip to content

Commit

Permalink
Merge pull request #1740 from mitchellh/ct-rtl
Browse files Browse the repository at this point in the history
coretext: force LTR font shaping
  • Loading branch information
mitchellh authored May 8, 2024
2 parents 18e5382 + 1cb70d6 commit e037c55
Show file tree
Hide file tree
Showing 5 changed files with 94 additions and 4 deletions.
1 change: 1 addition & 0 deletions pkg/macos/build.zig.zon
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
.{
.name = "macos",
.version = "0.1.0",
.paths = .{""},
.dependencies = .{
.apple_sdk = .{ .path = "../apple-sdk" },
},
Expand Down
1 change: 1 addition & 0 deletions pkg/macos/text.zig
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ pub usingnamespace @import("text/font_manager.zig");
pub usingnamespace @import("text/frame.zig");
pub usingnamespace @import("text/framesetter.zig");
pub usingnamespace @import("text/line.zig");
pub usingnamespace @import("text/paragraph_style.zig");
pub usingnamespace @import("text/run.zig");
pub usingnamespace @import("text/stylized_strings.zig");

Expand Down
49 changes: 49 additions & 0 deletions pkg/macos/text/paragraph_style.zig
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
const std = @import("std");
const assert = std.debug.assert;
const Allocator = std.mem.Allocator;
const foundation = @import("../foundation.zig");
const graphics = @import("../graphics.zig");
const text = @import("../text.zig");
const c = @import("c.zig");

// https://developer.apple.com/documentation/coretext/ctparagraphstyle?language=objc
pub const ParagraphStyle = opaque {
pub fn create(
settings: []const ParagraphStyleSetting,
) Allocator.Error!*ParagraphStyle {
return @ptrCast(@constCast(c.CTParagraphStyleCreate(
@ptrCast(settings.ptr),
settings.len,
)));
}

pub fn release(self: *ParagraphStyle) void {
foundation.CFRelease(self);
}
};

/// https://developer.apple.com/documentation/coretext/ctparagraphstylesetting?language=objc
pub const ParagraphStyleSetting = extern struct {
spec: ParagraphStyleSpecifier,
value_size: usize,
value: *const anyopaque,
};

/// https://developer.apple.com/documentation/coretext/ctparagraphstylespecifier?language=objc
pub const ParagraphStyleSpecifier = enum(c_uint) {
base_writing_direction = 13,
};

/// https://developer.apple.com/documentation/uikit/nswritingdirectionattributename?language=objc
pub const WritingDirection = enum(c_int) {
natural = -1,
ltr = 0,
rtl = 1,
lro = 2,
rlo = 3,
};

test ParagraphStyle {
const p = try ParagraphStyle.create(&.{});
defer p.release();
}
4 changes: 4 additions & 0 deletions pkg/macos/text/stylized_strings.zig
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,14 @@ const c = @import("c.zig");

pub const StringAttribute = enum {
font,
paragraph_style,
writing_direction,

pub fn key(self: StringAttribute) *foundation.String {
return @ptrFromInt(@intFromPtr(switch (self) {
.font => c.kCTFontAttributeName,
.paragraph_style => c.kCTParagraphStyleAttributeName,
.writing_direction => c.kCTWritingDirectionAttributeName,
}));
}
};
43 changes: 39 additions & 4 deletions src/font/shaper/coretext.zig
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,11 @@ pub const Shaper = struct {
/// The shared memory used for shaping results.
cell_buf: CellBuf,

/// The cached writing direction value for shaping. This isn't
/// configurable we just use this as a cache to avoid creating
/// and releasing many objects when shaping.
writing_direction: *macos.foundation.Array,

const CellBuf = std.ArrayListUnmanaged(font.shape.Cell);
const CodepointList = std.ArrayListUnmanaged(Codepoint);
const Codepoint = struct {
Expand Down Expand Up @@ -172,21 +177,45 @@ pub const Shaper = struct {
for (hardcoded_features) |name| try feats.append(name);
for (opts.features) |name| try feats.append(name);

const run_state = try RunState.init();
errdefer run_state.deinit();
var run_state = try RunState.init();
errdefer run_state.deinit(alloc);

// For now we only support LTR text. If we shape RTL text then
// rendering will be very wrong so we need to explicitly force
// LTR no matter what.
//
// See: https://github.com/mitchellh/ghostty/issues/1737
// See: https://github.com/mitchellh/ghostty/issues/1442
const writing_direction = array: {
const dir: macos.text.WritingDirection = .lro;
const num = try macos.foundation.Number.create(
.int,
&@intFromEnum(dir),
);
defer num.release();

var arr_init = [_]*const macos.foundation.Number{num};
break :array try macos.foundation.Array.create(
macos.foundation.Number,
&arr_init,
);
};
errdefer writing_direction.release();

return Shaper{
.alloc = alloc,
.cell_buf = .{},
.run_state = run_state,
.features = feats,
.writing_direction = writing_direction,
};
}

pub fn deinit(self: *Shaper) void {
self.cell_buf.deinit(self.alloc);
self.run_state.deinit(self.alloc);
self.features.deinit();
self.writing_direction.release();
}

pub fn runIterator(
Expand Down Expand Up @@ -276,8 +305,14 @@ pub const Shaper = struct {
// Get our font and use that get the attributes to set for the
// attributed string so the whole string uses the same font.
const attr_dict = dict: {
var keys = [_]?*const anyopaque{macos.text.StringAttribute.font.key()};
var values = [_]?*const anyopaque{run_font};
var keys = [_]?*const anyopaque{
macos.text.StringAttribute.font.key(),
macos.text.StringAttribute.writing_direction.key(),
};
var values = [_]?*const anyopaque{
run_font,
self.writing_direction,
};
break :dict try macos.foundation.Dictionary.create(&keys, &values);
};
defer attr_dict.release();
Expand Down

0 comments on commit e037c55

Please sign in to comment.