diff --git a/src/font/shaper/coretext.zig b/src/font/shaper/coretext.zig index 56e172aa3..2ea316637 100644 --- a/src/font/shaper/coretext.zig +++ b/src/font/shaper/coretext.zig @@ -232,7 +232,24 @@ pub const Shaper = struct { // Get our font. We have to apply the font features we want for // the font here. const run_font: *macos.text.Font = font: { - const face = try run.group.group.faceFromIndex(run.font_index); + // The CoreText shaper relies on CoreText and CoreText claims + // that CTFonts are threadsafe. See: + // https://developer.apple.com/documentation/coretext/ + // + // Quote: + // All individual functions in Core Text are thread-safe. Font + // objects (CTFont, CTFontDescriptor, and associated objects) can + // be used simultaneously by multiple operations, work queues, or + // threads. However, the layout objects (CTTypesetter, + // CTFramesetter, CTRun, CTLine, CTFrame, and associated objects) + // should be used in a single operation, work queue, or thread. + // + // Because of this, we only acquire the read lock to grab the + // face and set it up, then release it. + run.grid.lock.lockShared(); + defer run.grid.lock.unlockShared(); + + const face = try run.grid.resolver.collection.getFace(run.font_index); const original = face.font; const attrs = try self.features.attrsDict(face.quirks_disable_default_font_features); diff --git a/src/font/shaper/run.zig b/src/font/shaper/run.zig index 2d982411f..36e7ef2ab 100644 --- a/src/font/shaper/run.zig +++ b/src/font/shaper/run.zig @@ -174,7 +174,7 @@ pub const RunIterator = struct { // Otherwise we need a fallback character. Prefer the // official replacement character. - if (try self.group.indexForCodepoint( + if (try self.grid.getIndex( alloc, 0xFFFD, // replacement char font_style, @@ -182,7 +182,7 @@ pub const RunIterator = struct { )) |idx| break :font_info .{ .idx = idx, .fallback = 0xFFFD }; // Fallback to space - if (try self.group.indexForCodepoint( + if (try self.grid.getIndex( alloc, ' ', font_style, @@ -251,7 +251,7 @@ pub const RunIterator = struct { ) !?font.Collection.Index { // Get the font index for the primary codepoint. const primary_cp: u32 = if (cell.isEmpty() or cell.codepoint() == 0) ' ' else cell.codepoint(); - const primary = try self.group.indexForCodepoint( + const primary = try self.grid.getIndex( alloc, primary_cp, style, @@ -275,7 +275,7 @@ pub const RunIterator = struct { // Find a font that supports this codepoint. If none support this // then the whole grapheme can't be rendered so we return null. - const idx = try self.group.indexForCodepoint( + const idx = try self.grid.getIndex( alloc, cp, style, @@ -286,11 +286,11 @@ pub const RunIterator = struct { // We need to find a candidate that has ALL of our codepoints for (candidates.items) |idx| { - if (!self.group.group.hasCodepoint(idx, primary_cp, presentation)) continue; + if (!self.grid.hasCodepoint(idx, primary_cp, presentation)) continue; for (cps) |cp| { // Ignore Emoji ZWJs if (cp == 0xFE0E or cp == 0xFE0F or cp == 0x200D) continue; - if (!self.group.group.hasCodepoint(idx, cp, presentation)) break; + if (!self.grid.hasCodepoint(idx, cp, presentation)) break; } else { // If the while completed, then we have a candidate that // supports all of our codepoints.