mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-10-16 06:46:09 +00:00
font/freetype: introduce mutexes to ensure thread safety of Library and Face
For details see comments and FreeType docs @ https://freetype.org/freetype2/docs/reference/ft2-library_setup.html#ft_library https://freetype.org/freetype2/docs/reference/ft2-face_creation.html#ft_face tl;dr: FT_New_Face and FT_Done_Face require the Library to be locked for thread safety, and FT_Load_Glyph and FT_Render_Glyph and friends need the face to be locked for thread safety, since we're sharing faces across threads.
This commit is contained in:
@@ -380,7 +380,7 @@ test getIndex {
|
|||||||
const testEmoji = font.embedded.emoji;
|
const testEmoji = font.embedded.emoji;
|
||||||
const testEmojiText = font.embedded.emoji_text;
|
const testEmojiText = font.embedded.emoji_text;
|
||||||
|
|
||||||
var lib = try Library.init();
|
var lib = try Library.init(alloc);
|
||||||
defer lib.deinit();
|
defer lib.deinit();
|
||||||
|
|
||||||
var c = Collection.init();
|
var c = Collection.init();
|
||||||
@@ -461,7 +461,7 @@ test "getIndex disabled font style" {
|
|||||||
var atlas_grayscale = try font.Atlas.init(alloc, 512, .grayscale);
|
var atlas_grayscale = try font.Atlas.init(alloc, 512, .grayscale);
|
||||||
defer atlas_grayscale.deinit(alloc);
|
defer atlas_grayscale.deinit(alloc);
|
||||||
|
|
||||||
var lib = try Library.init();
|
var lib = try Library.init(alloc);
|
||||||
defer lib.deinit();
|
defer lib.deinit();
|
||||||
|
|
||||||
var c = Collection.init();
|
var c = Collection.init();
|
||||||
@@ -513,7 +513,7 @@ test "getIndex box glyph" {
|
|||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
|
|
||||||
var lib = try Library.init();
|
var lib = try Library.init(alloc);
|
||||||
defer lib.deinit();
|
defer lib.deinit();
|
||||||
|
|
||||||
const c = Collection.init();
|
const c = Collection.init();
|
||||||
|
@@ -78,8 +78,8 @@ pub const AddError = Allocator.Error || error{
|
|||||||
/// next in priority if others exist already, i.e. it'll be the _last_ to be
|
/// next in priority if others exist already, i.e. it'll be the _last_ to be
|
||||||
/// searched for a glyph in that list.
|
/// searched for a glyph in that list.
|
||||||
///
|
///
|
||||||
/// The collection takes ownership of the face. The face will be deallocated
|
/// If no error is encountered then the collection takes ownership of the face,
|
||||||
/// when the collection is deallocated.
|
/// in which case face will be deallocated when the collection is deallocated.
|
||||||
///
|
///
|
||||||
/// If a loaded face is added to the collection, it should be the same
|
/// If a loaded face is added to the collection, it should be the same
|
||||||
/// size as all the other faces in the collection. This function will not
|
/// size as all the other faces in the collection. This function will not
|
||||||
@@ -700,7 +700,7 @@ test "add full" {
|
|||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
const testFont = font.embedded.regular;
|
const testFont = font.embedded.regular;
|
||||||
|
|
||||||
var lib = try Library.init();
|
var lib = try Library.init(alloc);
|
||||||
defer lib.deinit();
|
defer lib.deinit();
|
||||||
|
|
||||||
var c = init();
|
var c = init();
|
||||||
@@ -746,7 +746,7 @@ test getFace {
|
|||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
const testFont = font.embedded.regular;
|
const testFont = font.embedded.regular;
|
||||||
|
|
||||||
var lib = try Library.init();
|
var lib = try Library.init(alloc);
|
||||||
defer lib.deinit();
|
defer lib.deinit();
|
||||||
|
|
||||||
var c = init();
|
var c = init();
|
||||||
@@ -770,7 +770,7 @@ test getIndex {
|
|||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
const testFont = font.embedded.regular;
|
const testFont = font.embedded.regular;
|
||||||
|
|
||||||
var lib = try Library.init();
|
var lib = try Library.init(alloc);
|
||||||
defer lib.deinit();
|
defer lib.deinit();
|
||||||
|
|
||||||
var c = init();
|
var c = init();
|
||||||
@@ -801,7 +801,7 @@ test completeStyles {
|
|||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
const testFont = font.embedded.regular;
|
const testFont = font.embedded.regular;
|
||||||
|
|
||||||
var lib = try Library.init();
|
var lib = try Library.init(alloc);
|
||||||
defer lib.deinit();
|
defer lib.deinit();
|
||||||
|
|
||||||
var c = init();
|
var c = init();
|
||||||
@@ -828,7 +828,7 @@ test setSize {
|
|||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
const testFont = font.embedded.regular;
|
const testFont = font.embedded.regular;
|
||||||
|
|
||||||
var lib = try Library.init();
|
var lib = try Library.init(alloc);
|
||||||
defer lib.deinit();
|
defer lib.deinit();
|
||||||
|
|
||||||
var c = init();
|
var c = init();
|
||||||
@@ -851,7 +851,7 @@ test hasCodepoint {
|
|||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
const testFont = font.embedded.regular;
|
const testFont = font.embedded.regular;
|
||||||
|
|
||||||
var lib = try Library.init();
|
var lib = try Library.init(alloc);
|
||||||
defer lib.deinit();
|
defer lib.deinit();
|
||||||
|
|
||||||
var c = init();
|
var c = init();
|
||||||
@@ -875,7 +875,7 @@ test "hasCodepoint emoji default graphical" {
|
|||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
const testEmoji = font.embedded.emoji;
|
const testEmoji = font.embedded.emoji;
|
||||||
|
|
||||||
var lib = try Library.init();
|
var lib = try Library.init(alloc);
|
||||||
defer lib.deinit();
|
defer lib.deinit();
|
||||||
|
|
||||||
var c = init();
|
var c = init();
|
||||||
@@ -898,7 +898,7 @@ test "metrics" {
|
|||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
const testFont = font.embedded.inconsolata;
|
const testFont = font.embedded.inconsolata;
|
||||||
|
|
||||||
var lib = try Library.init();
|
var lib = try Library.init(alloc);
|
||||||
defer lib.deinit();
|
defer lib.deinit();
|
||||||
|
|
||||||
var c = init();
|
var c = init();
|
||||||
|
@@ -407,7 +407,7 @@ test "fontconfig" {
|
|||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
|
|
||||||
// Load freetype
|
// Load freetype
|
||||||
var lib = try Library.init();
|
var lib = try Library.init(alloc);
|
||||||
defer lib.deinit();
|
defer lib.deinit();
|
||||||
|
|
||||||
// Get a deferred face from fontconfig
|
// Get a deferred face from fontconfig
|
||||||
@@ -437,7 +437,7 @@ test "coretext" {
|
|||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
|
|
||||||
// Load freetype
|
// Load freetype
|
||||||
var lib = try Library.init();
|
var lib = try Library.init(alloc);
|
||||||
defer lib.deinit();
|
defer lib.deinit();
|
||||||
|
|
||||||
// Get a deferred face from fontconfig
|
// Get a deferred face from fontconfig
|
||||||
|
@@ -338,7 +338,7 @@ test getIndex {
|
|||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
// const testEmoji = @import("test.zig").fontEmoji;
|
// const testEmoji = @import("test.zig").fontEmoji;
|
||||||
|
|
||||||
var lib = try Library.init();
|
var lib = try Library.init(alloc);
|
||||||
defer lib.deinit();
|
defer lib.deinit();
|
||||||
|
|
||||||
var grid = try testGrid(.normal, alloc, lib);
|
var grid = try testGrid(.normal, alloc, lib);
|
||||||
|
@@ -50,7 +50,7 @@ pub const InitError = Library.InitError;
|
|||||||
|
|
||||||
/// Initialize a new SharedGridSet.
|
/// Initialize a new SharedGridSet.
|
||||||
pub fn init(alloc: Allocator) InitError!SharedGridSet {
|
pub fn init(alloc: Allocator) InitError!SharedGridSet {
|
||||||
var font_lib = try Library.init();
|
var font_lib = try Library.init(alloc);
|
||||||
errdefer font_lib.deinit();
|
errdefer font_lib.deinit();
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
|
@@ -46,7 +46,11 @@ pub const Face = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// Initialize a CoreText-based font from a TTF/TTC in memory.
|
/// Initialize a CoreText-based font from a TTF/TTC in memory.
|
||||||
pub fn init(lib: font.Library, source: [:0]const u8, opts: font.face.Options) !Face {
|
pub fn init(
|
||||||
|
lib: font.Library,
|
||||||
|
source: [:0]const u8,
|
||||||
|
opts: font.face.Options,
|
||||||
|
) !Face {
|
||||||
_ = lib;
|
_ = lib;
|
||||||
|
|
||||||
const data = try macos.foundation.Data.createWithBytesNoCopy(source);
|
const data = try macos.foundation.Data.createWithBytesNoCopy(source);
|
||||||
@@ -914,7 +918,7 @@ test "in-memory" {
|
|||||||
var atlas = try font.Atlas.init(alloc, 512, .grayscale);
|
var atlas = try font.Atlas.init(alloc, 512, .grayscale);
|
||||||
defer atlas.deinit(alloc);
|
defer atlas.deinit(alloc);
|
||||||
|
|
||||||
var lib = try font.Library.init();
|
var lib = try font.Library.init(alloc);
|
||||||
defer lib.deinit();
|
defer lib.deinit();
|
||||||
|
|
||||||
var face = try Face.init(lib, testFont, .{ .size = .{ .points = 12 } });
|
var face = try Face.init(lib, testFont, .{ .size = .{ .points = 12 } });
|
||||||
@@ -941,7 +945,7 @@ test "variable" {
|
|||||||
var atlas = try font.Atlas.init(alloc, 512, .grayscale);
|
var atlas = try font.Atlas.init(alloc, 512, .grayscale);
|
||||||
defer atlas.deinit(alloc);
|
defer atlas.deinit(alloc);
|
||||||
|
|
||||||
var lib = try font.Library.init();
|
var lib = try font.Library.init(alloc);
|
||||||
defer lib.deinit();
|
defer lib.deinit();
|
||||||
|
|
||||||
var face = try Face.init(lib, testFont, .{ .size = .{ .points = 12 } });
|
var face = try Face.init(lib, testFont, .{ .size = .{ .points = 12 } });
|
||||||
@@ -968,7 +972,7 @@ test "variable set variation" {
|
|||||||
var atlas = try font.Atlas.init(alloc, 512, .grayscale);
|
var atlas = try font.Atlas.init(alloc, 512, .grayscale);
|
||||||
defer atlas.deinit(alloc);
|
defer atlas.deinit(alloc);
|
||||||
|
|
||||||
var lib = try font.Library.init();
|
var lib = try font.Library.init(alloc);
|
||||||
defer lib.deinit();
|
defer lib.deinit();
|
||||||
|
|
||||||
var face = try Face.init(lib, testFont, .{ .size = .{ .points = 12 } });
|
var face = try Face.init(lib, testFont, .{ .size = .{ .points = 12 } });
|
||||||
@@ -996,7 +1000,7 @@ test "svg font table" {
|
|||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
const testFont = font.embedded.julia_mono;
|
const testFont = font.embedded.julia_mono;
|
||||||
|
|
||||||
var lib = try font.Library.init();
|
var lib = try font.Library.init(alloc);
|
||||||
defer lib.deinit();
|
defer lib.deinit();
|
||||||
|
|
||||||
var face = try Face.init(lib, testFont, .{ .size = .{ .points = 12 } });
|
var face = try Face.init(lib, testFont, .{ .size = .{ .points = 12 } });
|
||||||
@@ -1010,9 +1014,10 @@ test "svg font table" {
|
|||||||
|
|
||||||
test "glyphIndex colored vs text" {
|
test "glyphIndex colored vs text" {
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
|
const alloc = testing.allocator;
|
||||||
const testFont = font.embedded.julia_mono;
|
const testFont = font.embedded.julia_mono;
|
||||||
|
|
||||||
var lib = try font.Library.init();
|
var lib = try font.Library.init(alloc);
|
||||||
defer lib.deinit();
|
defer lib.deinit();
|
||||||
|
|
||||||
var face = try Face.init(lib, testFont, .{ .size = .{ .points = 12 } });
|
var face = try Face.init(lib, testFont, .{ .size = .{ .points = 12 } });
|
||||||
|
@@ -29,12 +29,20 @@ pub const Face = struct {
|
|||||||
assert(font.face.FreetypeLoadFlags != void);
|
assert(font.face.FreetypeLoadFlags != void);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Our freetype library
|
/// Our Library
|
||||||
lib: freetype.Library,
|
lib: Library,
|
||||||
|
|
||||||
/// Our font face.
|
/// Our font face.
|
||||||
face: freetype.Face,
|
face: freetype.Face,
|
||||||
|
|
||||||
|
/// This mutex MUST be held while doing anything with the
|
||||||
|
/// glyph slot on the freetype face, because this struct
|
||||||
|
/// may be shared across multiple surfaces.
|
||||||
|
///
|
||||||
|
/// This means that anywhere where `self.face.loadGlyph`
|
||||||
|
/// is called, this mutex must be held.
|
||||||
|
ft_mutex: *std.Thread.Mutex,
|
||||||
|
|
||||||
/// Harfbuzz font corresponding to this face.
|
/// Harfbuzz font corresponding to this face.
|
||||||
hb_font: harfbuzz.Font,
|
hb_font: harfbuzz.Font,
|
||||||
|
|
||||||
@@ -59,30 +67,52 @@ pub const Face = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// Initialize a new font face with the given source in-memory.
|
/// Initialize a new font face with the given source in-memory.
|
||||||
pub fn initFile(lib: Library, path: [:0]const u8, index: i32, opts: font.face.Options) !Face {
|
pub fn initFile(
|
||||||
|
lib: Library,
|
||||||
|
path: [:0]const u8,
|
||||||
|
index: i32,
|
||||||
|
opts: font.face.Options,
|
||||||
|
) !Face {
|
||||||
|
lib.mutex.lock();
|
||||||
|
defer lib.mutex.unlock();
|
||||||
const face = try lib.lib.initFace(path, index);
|
const face = try lib.lib.initFace(path, index);
|
||||||
errdefer face.deinit();
|
errdefer face.deinit();
|
||||||
return try initFace(lib, face, opts);
|
return try initFace(lib, face, opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initialize a new font face with the given source in-memory.
|
/// Initialize a new font face with the given source in-memory.
|
||||||
pub fn init(lib: Library, source: [:0]const u8, opts: font.face.Options) !Face {
|
pub fn init(
|
||||||
|
lib: Library,
|
||||||
|
source: [:0]const u8,
|
||||||
|
opts: font.face.Options,
|
||||||
|
) !Face {
|
||||||
|
lib.mutex.lock();
|
||||||
|
defer lib.mutex.unlock();
|
||||||
const face = try lib.lib.initMemoryFace(source, 0);
|
const face = try lib.lib.initMemoryFace(source, 0);
|
||||||
errdefer face.deinit();
|
errdefer face.deinit();
|
||||||
return try initFace(lib, face, opts);
|
return try initFace(lib, face, opts);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn initFace(lib: Library, face: freetype.Face, opts: font.face.Options) !Face {
|
fn initFace(
|
||||||
|
lib: Library,
|
||||||
|
face: freetype.Face,
|
||||||
|
opts: font.face.Options,
|
||||||
|
) !Face {
|
||||||
try face.selectCharmap(.unicode);
|
try face.selectCharmap(.unicode);
|
||||||
try setSize_(face, opts.size);
|
try setSize_(face, opts.size);
|
||||||
|
|
||||||
var hb_font = try harfbuzz.freetype.createFont(face.handle);
|
var hb_font = try harfbuzz.freetype.createFont(face.handle);
|
||||||
errdefer hb_font.destroy();
|
errdefer hb_font.destroy();
|
||||||
|
|
||||||
|
const ft_mutex = try lib.alloc.create(std.Thread.Mutex);
|
||||||
|
errdefer lib.alloc.destroy(ft_mutex);
|
||||||
|
ft_mutex.* = .{};
|
||||||
|
|
||||||
var result: Face = .{
|
var result: Face = .{
|
||||||
.lib = lib.lib,
|
.lib = lib,
|
||||||
.face = face,
|
.face = face,
|
||||||
.hb_font = hb_font,
|
.hb_font = hb_font,
|
||||||
|
.ft_mutex = ft_mutex,
|
||||||
.load_flags = opts.freetype_load_flags,
|
.load_flags = opts.freetype_load_flags,
|
||||||
};
|
};
|
||||||
result.quirks_disable_default_font_features = quirks.disableDefaultFontFeatures(&result);
|
result.quirks_disable_default_font_features = quirks.disableDefaultFontFeatures(&result);
|
||||||
@@ -114,7 +144,13 @@ pub const Face = struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *Face) void {
|
pub fn deinit(self: *Face) void {
|
||||||
|
self.lib.alloc.destroy(self.ft_mutex);
|
||||||
|
{
|
||||||
|
self.lib.mutex.lock();
|
||||||
|
defer self.lib.mutex.unlock();
|
||||||
|
|
||||||
self.face.deinit();
|
self.face.deinit();
|
||||||
|
}
|
||||||
self.hb_font.destroy();
|
self.hb_font.destroy();
|
||||||
self.* = undefined;
|
self.* = undefined;
|
||||||
}
|
}
|
||||||
@@ -147,11 +183,7 @@ pub const Face = struct {
|
|||||||
self.face.ref();
|
self.face.ref();
|
||||||
errdefer self.face.deinit();
|
errdefer self.face.deinit();
|
||||||
|
|
||||||
var f = try initFace(
|
var f = try initFace(self.lib, self.face, opts);
|
||||||
.{ .lib = self.lib },
|
|
||||||
self.face,
|
|
||||||
opts,
|
|
||||||
);
|
|
||||||
errdefer f.deinit();
|
errdefer f.deinit();
|
||||||
f.synthetic = self.synthetic;
|
f.synthetic = self.synthetic;
|
||||||
f.synthetic.bold = true;
|
f.synthetic.bold = true;
|
||||||
@@ -166,11 +198,7 @@ pub const Face = struct {
|
|||||||
self.face.ref();
|
self.face.ref();
|
||||||
errdefer self.face.deinit();
|
errdefer self.face.deinit();
|
||||||
|
|
||||||
var f = try initFace(
|
var f = try initFace(self.lib, self.face, opts);
|
||||||
.{ .lib = self.lib },
|
|
||||||
self.face,
|
|
||||||
opts,
|
|
||||||
);
|
|
||||||
errdefer f.deinit();
|
errdefer f.deinit();
|
||||||
f.synthetic = self.synthetic;
|
f.synthetic = self.synthetic;
|
||||||
f.synthetic.italic = true;
|
f.synthetic.italic = true;
|
||||||
@@ -228,7 +256,7 @@ pub const Face = struct {
|
|||||||
// first thing we have to do is get all the vars and put them into
|
// first thing we have to do is get all the vars and put them into
|
||||||
// an array.
|
// an array.
|
||||||
const mm = try self.face.getMMVar();
|
const mm = try self.face.getMMVar();
|
||||||
defer self.lib.doneMMVar(mm);
|
defer self.lib.lib.doneMMVar(mm);
|
||||||
|
|
||||||
// To avoid allocations, we cap the number of variation axes we can
|
// To avoid allocations, we cap the number of variation axes we can
|
||||||
// support. This is arbitrary but Firefox caps this at 16 so I
|
// support. This is arbitrary but Firefox caps this at 16 so I
|
||||||
@@ -270,6 +298,9 @@ pub const Face = struct {
|
|||||||
|
|
||||||
/// Returns true if the given glyph ID is colorized.
|
/// Returns true if the given glyph ID is colorized.
|
||||||
pub fn isColorGlyph(self: *const Face, glyph_id: u32) bool {
|
pub fn isColorGlyph(self: *const Face, glyph_id: u32) bool {
|
||||||
|
self.ft_mutex.lock();
|
||||||
|
defer self.ft_mutex.unlock();
|
||||||
|
|
||||||
// Load the glyph and see what pixel mode it renders with.
|
// Load the glyph and see what pixel mode it renders with.
|
||||||
// All modes other than BGRA are non-color.
|
// All modes other than BGRA are non-color.
|
||||||
// If the glyph fails to load, just return false.
|
// If the glyph fails to load, just return false.
|
||||||
@@ -296,6 +327,9 @@ pub const Face = struct {
|
|||||||
glyph_index: u32,
|
glyph_index: u32,
|
||||||
opts: font.face.RenderOptions,
|
opts: font.face.RenderOptions,
|
||||||
) !Glyph {
|
) !Glyph {
|
||||||
|
self.ft_mutex.lock();
|
||||||
|
defer self.ft_mutex.unlock();
|
||||||
|
|
||||||
const metrics = opts.grid_metrics;
|
const metrics = opts.grid_metrics;
|
||||||
|
|
||||||
// If we have synthetic italic, then we apply a transformation matrix.
|
// If we have synthetic italic, then we apply a transformation matrix.
|
||||||
@@ -741,6 +775,9 @@ pub const Face = struct {
|
|||||||
// If we fail to load any visible ASCII we just use max_advance from
|
// If we fail to load any visible ASCII we just use max_advance from
|
||||||
// the metrics provided by FreeType.
|
// the metrics provided by FreeType.
|
||||||
const cell_width: f64 = cell_width: {
|
const cell_width: f64 = cell_width: {
|
||||||
|
self.ft_mutex.lock();
|
||||||
|
defer self.ft_mutex.unlock();
|
||||||
|
|
||||||
var max: f64 = 0.0;
|
var max: f64 = 0.0;
|
||||||
var c: u8 = ' ';
|
var c: u8 = ' ';
|
||||||
while (c < 127) : (c += 1) {
|
while (c < 127) : (c += 1) {
|
||||||
@@ -780,6 +817,8 @@ pub const Face = struct {
|
|||||||
|
|
||||||
break :heights .{
|
break :heights .{
|
||||||
cap: {
|
cap: {
|
||||||
|
self.ft_mutex.lock();
|
||||||
|
defer self.ft_mutex.unlock();
|
||||||
if (face.getCharIndex('H')) |glyph_index| {
|
if (face.getCharIndex('H')) |glyph_index| {
|
||||||
if (face.loadGlyph(glyph_index, .{
|
if (face.loadGlyph(glyph_index, .{
|
||||||
.render = true,
|
.render = true,
|
||||||
@@ -791,6 +830,8 @@ pub const Face = struct {
|
|||||||
break :cap null;
|
break :cap null;
|
||||||
},
|
},
|
||||||
ex: {
|
ex: {
|
||||||
|
self.ft_mutex.lock();
|
||||||
|
defer self.ft_mutex.unlock();
|
||||||
if (face.getCharIndex('x')) |glyph_index| {
|
if (face.getCharIndex('x')) |glyph_index| {
|
||||||
if (face.loadGlyph(glyph_index, .{
|
if (face.loadGlyph(glyph_index, .{
|
||||||
.render = true,
|
.render = true,
|
||||||
@@ -832,7 +873,7 @@ test {
|
|||||||
const testFont = font.embedded.inconsolata;
|
const testFont = font.embedded.inconsolata;
|
||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
|
|
||||||
var lib = try Library.init();
|
var lib = try Library.init(alloc);
|
||||||
defer lib.deinit();
|
defer lib.deinit();
|
||||||
|
|
||||||
var atlas = try font.Atlas.init(alloc, 512, .grayscale);
|
var atlas = try font.Atlas.init(alloc, 512, .grayscale);
|
||||||
@@ -881,7 +922,7 @@ test "color emoji" {
|
|||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
const testFont = font.embedded.emoji;
|
const testFont = font.embedded.emoji;
|
||||||
|
|
||||||
var lib = try Library.init();
|
var lib = try Library.init(alloc);
|
||||||
defer lib.deinit();
|
defer lib.deinit();
|
||||||
|
|
||||||
var atlas = try font.Atlas.init(alloc, 512, .rgba);
|
var atlas = try font.Atlas.init(alloc, 512, .rgba);
|
||||||
@@ -936,7 +977,7 @@ test "mono to rgba" {
|
|||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
const testFont = font.embedded.emoji;
|
const testFont = font.embedded.emoji;
|
||||||
|
|
||||||
var lib = try Library.init();
|
var lib = try Library.init(alloc);
|
||||||
defer lib.deinit();
|
defer lib.deinit();
|
||||||
|
|
||||||
var atlas = try font.Atlas.init(alloc, 512, .rgba);
|
var atlas = try font.Atlas.init(alloc, 512, .rgba);
|
||||||
@@ -958,7 +999,7 @@ test "svg font table" {
|
|||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
const testFont = font.embedded.julia_mono;
|
const testFont = font.embedded.julia_mono;
|
||||||
|
|
||||||
var lib = try font.Library.init();
|
var lib = try font.Library.init(alloc);
|
||||||
defer lib.deinit();
|
defer lib.deinit();
|
||||||
|
|
||||||
var face = try Face.init(lib, testFont, .{ .size = .{ .points = 12, .xdpi = 72, .ydpi = 72 } });
|
var face = try Face.init(lib, testFont, .{ .size = .{ .points = 12, .xdpi = 72, .ydpi = 72 } });
|
||||||
@@ -995,7 +1036,7 @@ test "bitmap glyph" {
|
|||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
const testFont = font.embedded.terminus_ttf;
|
const testFont = font.embedded.terminus_ttf;
|
||||||
|
|
||||||
var lib = try Library.init();
|
var lib = try Library.init(alloc);
|
||||||
defer lib.deinit();
|
defer lib.deinit();
|
||||||
|
|
||||||
var atlas = try font.Atlas.init(alloc, 512, .grayscale);
|
var atlas = try font.Atlas.init(alloc, 512, .grayscale);
|
||||||
|
@@ -1,5 +1,7 @@
|
|||||||
//! A library represents the shared state that the underlying font
|
//! A library represents the shared state that the underlying font
|
||||||
//! library implementation(s) require per-process.
|
//! library implementation(s) require per-process.
|
||||||
|
const std = @import("std");
|
||||||
|
const Allocator = std.mem.Allocator;
|
||||||
const builtin = @import("builtin");
|
const builtin = @import("builtin");
|
||||||
const options = @import("main.zig").options;
|
const options = @import("main.zig").options;
|
||||||
const freetype = @import("freetype");
|
const freetype = @import("freetype");
|
||||||
@@ -24,13 +26,26 @@ pub const Library = switch (options.backend) {
|
|||||||
pub const FreetypeLibrary = struct {
|
pub const FreetypeLibrary = struct {
|
||||||
lib: freetype.Library,
|
lib: freetype.Library,
|
||||||
|
|
||||||
pub const InitError = freetype.Error;
|
alloc: Allocator,
|
||||||
|
|
||||||
pub fn init() InitError!Library {
|
/// Mutex to be held any time the library is
|
||||||
return Library{ .lib = try freetype.Library.init() };
|
/// being used to create or destroy a face.
|
||||||
|
mutex: *std.Thread.Mutex,
|
||||||
|
|
||||||
|
pub const InitError = freetype.Error || Allocator.Error;
|
||||||
|
|
||||||
|
pub fn init(alloc: Allocator) InitError!Library {
|
||||||
|
const lib = try freetype.Library.init();
|
||||||
|
errdefer lib.deinit();
|
||||||
|
|
||||||
|
const mutex = try alloc.create(std.Thread.Mutex);
|
||||||
|
mutex.* = .{};
|
||||||
|
|
||||||
|
return Library{ .lib = lib, .alloc = alloc, .mutex = mutex };
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn deinit(self: *Library) void {
|
pub fn deinit(self: *Library) void {
|
||||||
|
self.alloc.destroy(self.mutex);
|
||||||
self.lib.deinit();
|
self.lib.deinit();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
@@ -38,7 +53,8 @@ pub const FreetypeLibrary = struct {
|
|||||||
pub const NoopLibrary = struct {
|
pub const NoopLibrary = struct {
|
||||||
pub const InitError = error{};
|
pub const InitError = error{};
|
||||||
|
|
||||||
pub fn init() InitError!Library {
|
pub fn init(alloc: Allocator) InitError!Library {
|
||||||
|
_ = alloc;
|
||||||
return Library{};
|
return Library{};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -99,7 +99,7 @@ test "SVG" {
|
|||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
const testFont = font.embedded.julia_mono;
|
const testFont = font.embedded.julia_mono;
|
||||||
|
|
||||||
var lib = try font.Library.init();
|
var lib = try font.Library.init(alloc);
|
||||||
defer lib.deinit();
|
defer lib.deinit();
|
||||||
|
|
||||||
var face = try font.Face.init(lib, testFont, .{ .size = .{ .points = 12 } });
|
var face = try font.Face.init(lib, testFont, .{ .size = .{ .points = 12 } });
|
||||||
|
@@ -1761,7 +1761,7 @@ fn testShaperWithFont(alloc: Allocator, font_req: TestFont) !TestShaper {
|
|||||||
.nerd_font => font.embedded.nerd_font,
|
.nerd_font => font.embedded.nerd_font,
|
||||||
};
|
};
|
||||||
|
|
||||||
var lib = try Library.init();
|
var lib = try Library.init(alloc);
|
||||||
errdefer lib.deinit();
|
errdefer lib.deinit();
|
||||||
|
|
||||||
var c = Collection.init();
|
var c = Collection.init();
|
||||||
|
@@ -1220,7 +1220,7 @@ fn testShaperWithFont(alloc: Allocator, font_req: TestFont) !TestShaper {
|
|||||||
.arabic => font.embedded.arabic,
|
.arabic => font.embedded.arabic,
|
||||||
};
|
};
|
||||||
|
|
||||||
var lib = try Library.init();
|
var lib = try Library.init(alloc);
|
||||||
errdefer lib.deinit();
|
errdefer lib.deinit();
|
||||||
|
|
||||||
var c = Collection.init();
|
var c = Collection.init();
|
||||||
|
Reference in New Issue
Block a user