mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-07-16 16:56:09 +03:00
Merge pull request #61 from mitchellh/font-group
wasm: Discovery, DeferredFace, Group, GroupCache
This commit is contained in:
@ -28,6 +28,20 @@ fetch(url.href).then(response =>
|
|||||||
face_free,
|
face_free,
|
||||||
face_render_glyph,
|
face_render_glyph,
|
||||||
face_debug_canvas,
|
face_debug_canvas,
|
||||||
|
deferred_face_new,
|
||||||
|
deferred_face_free,
|
||||||
|
deferred_face_load,
|
||||||
|
deferred_face_face,
|
||||||
|
group_new,
|
||||||
|
group_free,
|
||||||
|
group_add_face,
|
||||||
|
group_index_for_codepoint,
|
||||||
|
group_render_glyph,
|
||||||
|
group_cache_new,
|
||||||
|
group_cache_free,
|
||||||
|
group_cache_index_for_codepoint,
|
||||||
|
group_cache_render_glyph,
|
||||||
|
group_cache_atlas_greyscale,
|
||||||
atlas_new,
|
atlas_new,
|
||||||
atlas_free,
|
atlas_free,
|
||||||
atlas_debug_canvas,
|
atlas_debug_canvas,
|
||||||
@ -40,28 +54,43 @@ fetch(url.href).then(response =>
|
|||||||
zjs.memory = memory;
|
zjs.memory = memory;
|
||||||
|
|
||||||
// Create our atlas
|
// Create our atlas
|
||||||
const atlas = atlas_new(512, 0 /* greyscale */);
|
// const atlas = atlas_new(512, 0 /* greyscale */);
|
||||||
|
|
||||||
// Create some memory for our string
|
// Create some memory for our string
|
||||||
const font = new TextEncoder().encode("monospace");
|
const font = new TextEncoder().encode("monospace");
|
||||||
const font_ptr = malloc(font.byteLength);
|
const font_ptr = malloc(font.byteLength);
|
||||||
new Uint8Array(memory.buffer, font_ptr).set(font);
|
new Uint8Array(memory.buffer, font_ptr).set(font);
|
||||||
|
|
||||||
|
// Initialize our deferred face
|
||||||
|
const df = deferred_face_new(font_ptr, font.byteLength);
|
||||||
|
//deferred_face_load(df, 72 /* size */);
|
||||||
|
//const face = deferred_face_face(df);
|
||||||
|
|
||||||
// Initialize our font face
|
// Initialize our font face
|
||||||
const face = face_new(font_ptr, font.byteLength, 72 /* size in px */);
|
//const face = face_new(font_ptr, font.byteLength, 72 /* size in px */);
|
||||||
free(font_ptr);
|
free(font_ptr);
|
||||||
|
|
||||||
|
// Create our group
|
||||||
|
const group = group_new(72 /* size */);
|
||||||
|
group_add_face(group, 0, df);
|
||||||
|
|
||||||
|
// Create our group cache
|
||||||
|
const group_cache = group_cache_new(group);
|
||||||
|
|
||||||
// Render a glyph
|
// Render a glyph
|
||||||
for (let i = 33; i <= 126; i++) {
|
for (let i = 33; i <= 126; i++) {
|
||||||
face_render_glyph(face, atlas, i);
|
const font_idx = group_cache_index_for_codepoint(group_cache, i, 0, -1);
|
||||||
|
group_cache_render_glyph(group_cache, font_idx, i, 0);
|
||||||
|
//face_render_glyph(face, atlas, i);
|
||||||
}
|
}
|
||||||
//face_render_glyph(face, atlas, "橋".codePointAt(0));
|
//face_render_glyph(face, atlas, "橋".codePointAt(0));
|
||||||
//face_render_glyph(face, atlas, "p".codePointAt(0));
|
//face_render_glyph(face, atlas, "p".codePointAt(0));
|
||||||
|
|
||||||
// Debug our canvas
|
// Debug our canvas
|
||||||
face_debug_canvas(face);
|
//face_debug_canvas(face);
|
||||||
|
|
||||||
// Debug our atlas canvas
|
// Debug our atlas canvas
|
||||||
|
const atlas = group_cache_atlas_greyscale(group_cache);
|
||||||
const id = atlas_debug_canvas(atlas);
|
const id = atlas_debug_canvas(atlas);
|
||||||
document.getElementById("atlas-canvas").append(zjs.deleteValue(id));
|
document.getElementById("atlas-canvas").append(zjs.deleteValue(id));
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ const DeferredFace = @This();
|
|||||||
|
|
||||||
const std = @import("std");
|
const std = @import("std");
|
||||||
const assert = std.debug.assert;
|
const assert = std.debug.assert;
|
||||||
|
const Allocator = std.mem.Allocator;
|
||||||
const fontconfig = @import("fontconfig");
|
const fontconfig = @import("fontconfig");
|
||||||
const macos = @import("macos");
|
const macos = @import("macos");
|
||||||
const font = @import("main.zig");
|
const font = @import("main.zig");
|
||||||
@ -16,6 +17,8 @@ const Library = @import("main.zig").Library;
|
|||||||
const Face = @import("main.zig").Face;
|
const Face = @import("main.zig").Face;
|
||||||
const Presentation = @import("main.zig").Presentation;
|
const Presentation = @import("main.zig").Presentation;
|
||||||
|
|
||||||
|
const log = std.log.scoped(.deferred_face);
|
||||||
|
|
||||||
/// The loaded face (once loaded).
|
/// The loaded face (once loaded).
|
||||||
face: ?Face = null,
|
face: ?Face = null,
|
||||||
|
|
||||||
@ -27,6 +30,10 @@ fc: if (options.backend == .fontconfig_freetype) ?Fontconfig else void =
|
|||||||
ct: if (font.Discover == font.discovery.CoreText) ?CoreText else void =
|
ct: if (font.Discover == font.discovery.CoreText) ?CoreText else void =
|
||||||
if (font.Discover == font.discovery.CoreText) null else {},
|
if (font.Discover == font.discovery.CoreText) null else {},
|
||||||
|
|
||||||
|
/// Canvas
|
||||||
|
wc: if (options.backend == .web_canvas) ?WebCanvas else void =
|
||||||
|
if (options.backend == .web_canvas) null else {},
|
||||||
|
|
||||||
/// Fontconfig specific data. This is only present if building with fontconfig.
|
/// Fontconfig specific data. This is only present if building with fontconfig.
|
||||||
pub const Fontconfig = struct {
|
pub const Fontconfig = struct {
|
||||||
/// The pattern for this font. This must be the "render prepared" pattern.
|
/// The pattern for this font. This must be the "render prepared" pattern.
|
||||||
@ -56,6 +63,20 @@ pub const CoreText = struct {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// WebCanvas specific data. This is only present when building with canvas.
|
||||||
|
pub const WebCanvas = struct {
|
||||||
|
/// The allocator to use for fonts
|
||||||
|
alloc: Allocator,
|
||||||
|
|
||||||
|
/// The string to use for the "font" attribute for the canvas
|
||||||
|
font_str: [:0]const u8,
|
||||||
|
|
||||||
|
pub fn deinit(self: *WebCanvas) void {
|
||||||
|
self.alloc.free(self.font_str);
|
||||||
|
self.* = undefined;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
/// Initialize a deferred face that is already pre-loaded. The deferred face
|
/// Initialize a deferred face that is already pre-loaded. The deferred face
|
||||||
/// takes ownership over the loaded face, deinit will deinit the loaded face.
|
/// takes ownership over the loaded face, deinit will deinit the loaded face.
|
||||||
pub fn initLoaded(face: Face) DeferredFace {
|
pub fn initLoaded(face: Face) DeferredFace {
|
||||||
@ -68,8 +89,7 @@ pub fn deinit(self: *DeferredFace) void {
|
|||||||
.fontconfig_freetype => if (self.fc) |*fc| fc.deinit(),
|
.fontconfig_freetype => if (self.fc) |*fc| fc.deinit(),
|
||||||
.coretext, .coretext_freetype => if (self.ct) |*ct| ct.deinit(),
|
.coretext, .coretext_freetype => if (self.ct) |*ct| ct.deinit(),
|
||||||
.freetype => {},
|
.freetype => {},
|
||||||
// TODO
|
.web_canvas => if (self.wc) |*wc| wc.deinit(),
|
||||||
.web_canvas => unreachable,
|
|
||||||
}
|
}
|
||||||
self.* = undefined;
|
self.* = undefined;
|
||||||
}
|
}
|
||||||
@ -83,6 +103,8 @@ pub inline fn loaded(self: DeferredFace) bool {
|
|||||||
/// face so it doesn't have to be freed.
|
/// face so it doesn't have to be freed.
|
||||||
pub fn name(self: DeferredFace) ![:0]const u8 {
|
pub fn name(self: DeferredFace) ![:0]const u8 {
|
||||||
switch (options.backend) {
|
switch (options.backend) {
|
||||||
|
.freetype => {},
|
||||||
|
|
||||||
.fontconfig_freetype => if (self.fc) |fc|
|
.fontconfig_freetype => if (self.fc) |fc|
|
||||||
return (try fc.pattern.get(.fullname, 0)).string,
|
return (try fc.pattern.get(.fullname, 0)).string,
|
||||||
|
|
||||||
@ -91,10 +113,7 @@ pub fn name(self: DeferredFace) ![:0]const u8 {
|
|||||||
return display_name.cstringPtr(.utf8) orelse "<unsupported internal encoding>";
|
return display_name.cstringPtr(.utf8) orelse "<unsupported internal encoding>";
|
||||||
},
|
},
|
||||||
|
|
||||||
.freetype => {},
|
.web_canvas => if (self.wc) |wc| return wc.font_str,
|
||||||
|
|
||||||
// TODO
|
|
||||||
.web_canvas => unreachable,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return "TODO: built-in font names";
|
return "TODO: built-in font names";
|
||||||
@ -125,8 +144,10 @@ pub fn load(
|
|||||||
return;
|
return;
|
||||||
},
|
},
|
||||||
|
|
||||||
// TODO
|
.web_canvas => {
|
||||||
.web_canvas => unreachable,
|
try self.loadWebCanvas(size);
|
||||||
|
return;
|
||||||
|
},
|
||||||
|
|
||||||
// Unreachable because we must be already loaded or have the
|
// Unreachable because we must be already loaded or have the
|
||||||
// proper configuration for one of the other deferred mechanisms.
|
// proper configuration for one of the other deferred mechanisms.
|
||||||
@ -200,6 +221,15 @@ fn loadCoreTextFreetype(
|
|||||||
self.face = try Face.initFile(lib, buf[0..path_slice.len :0], 0, size);
|
self.face = try Face.initFile(lib, buf[0..path_slice.len :0], 0, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn loadWebCanvas(
|
||||||
|
self: *DeferredFace,
|
||||||
|
size: font.face.DesiredSize,
|
||||||
|
) !void {
|
||||||
|
assert(self.face == null);
|
||||||
|
const wc = self.wc.?;
|
||||||
|
self.face = try Face.initNamed(wc.alloc, wc.font_str, size);
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns true if this face can satisfy the given codepoint and
|
/// Returns true if this face can satisfy the given codepoint and
|
||||||
/// presentation. If presentation is null, then it just checks if the
|
/// presentation. If presentation is null, then it just checks if the
|
||||||
/// codepoint is present at all.
|
/// codepoint is present at all.
|
||||||
@ -251,8 +281,9 @@ pub fn hasCodepoint(self: DeferredFace, cp: u32, p: ?Presentation) bool {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// TODO
|
// Canvas always has the codepoint because we have no way of
|
||||||
.web_canvas => unreachable,
|
// really checking and we let the browser handle it.
|
||||||
|
.web_canvas => return true,
|
||||||
|
|
||||||
.freetype => {},
|
.freetype => {},
|
||||||
}
|
}
|
||||||
@ -262,6 +293,57 @@ pub fn hasCodepoint(self: DeferredFace, cp: u32, p: ?Presentation) bool {
|
|||||||
unreachable;
|
unreachable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The wasm-compatible API.
|
||||||
|
pub const Wasm = struct {
|
||||||
|
const wasm = @import("../os/wasm.zig");
|
||||||
|
const alloc = wasm.alloc;
|
||||||
|
|
||||||
|
export fn deferred_face_new(ptr: [*]const u8, len: usize) ?*DeferredFace {
|
||||||
|
return deferred_face_new_(ptr, len) catch |err| {
|
||||||
|
log.warn("error creating deferred face err={}", .{err});
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deferred_face_new_(ptr: [*]const u8, len: usize) !*DeferredFace {
|
||||||
|
var font_str = try alloc.dupeZ(u8, ptr[0..len]);
|
||||||
|
errdefer alloc.free(font_str);
|
||||||
|
|
||||||
|
var face: DeferredFace = .{
|
||||||
|
.wc = .{
|
||||||
|
.alloc = alloc,
|
||||||
|
.font_str = font_str,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
errdefer face.deinit();
|
||||||
|
|
||||||
|
var result = try alloc.create(DeferredFace);
|
||||||
|
errdefer alloc.destroy(result);
|
||||||
|
result.* = face;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn deferred_face_free(ptr: ?*DeferredFace) void {
|
||||||
|
if (ptr) |v| {
|
||||||
|
v.deinit();
|
||||||
|
alloc.destroy(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn deferred_face_load(self: *DeferredFace, pts: u16) void {
|
||||||
|
self.load(.{}, .{ .points = pts }) catch |err| {
|
||||||
|
log.warn("error loading deferred face err={}", .{err});
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Caller should not free this, the face is owned by the deferred face.
|
||||||
|
export fn deferred_face_face(self: *DeferredFace) ?*Face {
|
||||||
|
assert(self.loaded());
|
||||||
|
return &self.face.?;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
test "preloaded" {
|
test "preloaded" {
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
const testFont = @import("test.zig").fontRegular;
|
const testFont = @import("test.zig").fontRegular;
|
||||||
|
@ -119,7 +119,7 @@ pub fn setSize(self: *Group, size: font.face.DesiredSize) !void {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// This represents a specific font in the group.
|
/// This represents a specific font in the group.
|
||||||
pub const FontIndex = packed struct {
|
pub const FontIndex = packed struct(u8) {
|
||||||
/// The number of bits we use for the index.
|
/// The number of bits we use for the index.
|
||||||
const idx_bits = 8 - @typeInfo(@typeInfo(Style).Enum.tag_type).Int.bits;
|
const idx_bits = 8 - @typeInfo(@typeInfo(Style).Enum.tag_type).Int.bits;
|
||||||
pub const IndexInt = @Type(.{ .Int = .{ .signedness = .unsigned, .bits = idx_bits } });
|
pub const IndexInt = @Type(.{ .Int = .{ .signedness = .unsigned, .bits = idx_bits } });
|
||||||
@ -272,13 +272,16 @@ pub fn renderGlyph(
|
|||||||
max_height: ?u16,
|
max_height: ?u16,
|
||||||
) !Glyph {
|
) !Glyph {
|
||||||
// Special-case fonts are rendered directly.
|
// Special-case fonts are rendered directly.
|
||||||
if (index.special()) |sp| switch (sp) {
|
// TODO: web_canvas
|
||||||
.sprite => return try self.sprite.?.renderGlyph(
|
if (options.backend != .web_canvas) {
|
||||||
alloc,
|
if (index.special()) |sp| switch (sp) {
|
||||||
atlas,
|
.sprite => return try self.sprite.?.renderGlyph(
|
||||||
glyph_index,
|
alloc,
|
||||||
),
|
atlas,
|
||||||
};
|
glyph_index,
|
||||||
|
),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
const face = &self.faces.get(index.style).items[@intCast(usize, index.idx)];
|
const face = &self.faces.get(index.style).items[@intCast(usize, index.idx)];
|
||||||
try face.load(self.lib, self.size);
|
try face.load(self.lib, self.size);
|
||||||
@ -303,6 +306,68 @@ pub const Wasm = struct {
|
|||||||
result.* = group;
|
result.* = group;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export fn group_free(ptr: ?*Group) void {
|
||||||
|
if (ptr) |v| {
|
||||||
|
v.deinit();
|
||||||
|
alloc.destroy(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn group_add_face(self: *Group, style: u16, face: *font.DeferredFace) void {
|
||||||
|
return self.addFace(alloc, @intToEnum(Style, style), face.*) catch |err| {
|
||||||
|
log.warn("error adding face to group err={}", .{err});
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn group_set_size(self: *Group, size: u16) void {
|
||||||
|
return self.setSize(.{ .points = size }) catch |err| {
|
||||||
|
log.warn("error setting group size err={}", .{err});
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Presentation is negative for doesn't matter.
|
||||||
|
export fn group_index_for_codepoint(self: *Group, cp: u32, style: u16, p: i16) i16 {
|
||||||
|
const presentation = if (p < 0) null else @intToEnum(Presentation, p);
|
||||||
|
const idx = self.indexForCodepoint(
|
||||||
|
cp,
|
||||||
|
@intToEnum(Style, style),
|
||||||
|
presentation,
|
||||||
|
) orelse return -1;
|
||||||
|
return @intCast(i16, @bitCast(u8, idx));
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn group_render_glyph(
|
||||||
|
self: *Group,
|
||||||
|
atlas: *font.Atlas,
|
||||||
|
idx: i16,
|
||||||
|
cp: u32,
|
||||||
|
max_height: u16,
|
||||||
|
) ?*Glyph {
|
||||||
|
return group_render_glyph_(self, atlas, idx, cp, max_height) catch |err| {
|
||||||
|
log.warn("error rendering group glyph err={}", .{err});
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn group_render_glyph_(
|
||||||
|
self: *Group,
|
||||||
|
atlas: *font.Atlas,
|
||||||
|
idx_: i16,
|
||||||
|
cp: u32,
|
||||||
|
max_height_: u16,
|
||||||
|
) !*Glyph {
|
||||||
|
const idx = @bitCast(FontIndex, @intCast(u8, idx_));
|
||||||
|
const max_height = if (max_height_ <= 0) null else max_height_;
|
||||||
|
const glyph = try self.renderGlyph(alloc, atlas, idx, cp, max_height);
|
||||||
|
|
||||||
|
var result = try alloc.create(Glyph);
|
||||||
|
errdefer alloc.destroy(result);
|
||||||
|
result.* = glyph;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
test {
|
test {
|
||||||
|
@ -231,6 +231,88 @@ test {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The wasm-compatible API.
|
||||||
|
pub const Wasm = struct {
|
||||||
|
const wasm = @import("../os/wasm.zig");
|
||||||
|
const alloc = wasm.alloc;
|
||||||
|
|
||||||
|
export fn group_cache_new(group: *Group) ?*GroupCache {
|
||||||
|
return group_cache_new_(group) catch null;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn group_cache_new_(group: *Group) !*GroupCache {
|
||||||
|
var gc = try GroupCache.init(alloc, group.*);
|
||||||
|
errdefer gc.deinit(alloc);
|
||||||
|
|
||||||
|
var result = try alloc.create(GroupCache);
|
||||||
|
errdefer alloc.destroy(result);
|
||||||
|
result.* = gc;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn group_cache_free(ptr: ?*GroupCache) void {
|
||||||
|
if (ptr) |v| {
|
||||||
|
v.deinit(alloc);
|
||||||
|
alloc.destroy(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn group_cache_set_size(self: *GroupCache, size: u16) void {
|
||||||
|
return self.setSize(.{ .points = size }) catch |err| {
|
||||||
|
log.warn("error setting group cache size err={}", .{err});
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Presentation is negative for doesn't matter.
|
||||||
|
export fn group_cache_index_for_codepoint(self: *GroupCache, cp: u32, style: u16, p: i16) i16 {
|
||||||
|
const presentation = if (p < 0) null else @intToEnum(Presentation, p);
|
||||||
|
if (self.indexForCodepoint(
|
||||||
|
alloc,
|
||||||
|
cp,
|
||||||
|
@intToEnum(Style, style),
|
||||||
|
presentation,
|
||||||
|
)) |idx| {
|
||||||
|
return @intCast(i16, @bitCast(u8, idx orelse return -1));
|
||||||
|
} else |err| {
|
||||||
|
log.warn("error getting index for codepoint from group cache size err={}", .{err});
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn group_cache_render_glyph(
|
||||||
|
self: *GroupCache,
|
||||||
|
idx: i16,
|
||||||
|
cp: u32,
|
||||||
|
max_height: u16,
|
||||||
|
) ?*Glyph {
|
||||||
|
return group_cache_render_glyph_(self, idx, cp, max_height) catch |err| {
|
||||||
|
log.warn("error rendering group cache glyph err={}", .{err});
|
||||||
|
return null;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
fn group_cache_render_glyph_(
|
||||||
|
self: *GroupCache,
|
||||||
|
idx_: i16,
|
||||||
|
cp: u32,
|
||||||
|
max_height_: u16,
|
||||||
|
) !*Glyph {
|
||||||
|
const idx = @bitCast(Group.FontIndex, @intCast(u8, idx_));
|
||||||
|
const max_height = if (max_height_ <= 0) null else max_height_;
|
||||||
|
const glyph = try self.renderGlyph(alloc, idx, cp, max_height);
|
||||||
|
|
||||||
|
var result = try alloc.create(Glyph);
|
||||||
|
errdefer alloc.destroy(result);
|
||||||
|
result.* = glyph;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
export fn group_cache_atlas_greyscale(self: *GroupCache) *font.Atlas {
|
||||||
|
return &self.atlas_greyscale;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
test "resize" {
|
test "resize" {
|
||||||
const testing = std.testing;
|
const testing = std.testing;
|
||||||
const alloc = testing.allocator;
|
const alloc = testing.allocator;
|
||||||
|
@ -10,9 +10,10 @@ const log = std.log.scoped(.discovery);
|
|||||||
|
|
||||||
/// Discover implementation for the compile options.
|
/// Discover implementation for the compile options.
|
||||||
pub const Discover = switch (options.backend) {
|
pub const Discover = switch (options.backend) {
|
||||||
|
.freetype => void, // no discovery
|
||||||
.fontconfig_freetype => Fontconfig,
|
.fontconfig_freetype => Fontconfig,
|
||||||
.coretext => CoreText,
|
.coretext, .coretext_freetype => CoreText,
|
||||||
else => void,
|
.web_canvas => void, // no discovery
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Descriptor is used to search for fonts. The only required field
|
/// Descriptor is used to search for fonts. The only required field
|
||||||
|
@ -20,7 +20,9 @@ pub usingnamespace @import("library.zig");
|
|||||||
/// If we're targeting wasm then we export some wasm APIs.
|
/// If we're targeting wasm then we export some wasm APIs.
|
||||||
pub usingnamespace if (builtin.target.isWasm()) struct {
|
pub usingnamespace if (builtin.target.isWasm()) struct {
|
||||||
pub usingnamespace Atlas.Wasm;
|
pub usingnamespace Atlas.Wasm;
|
||||||
|
pub usingnamespace DeferredFace.Wasm;
|
||||||
pub usingnamespace Group.Wasm;
|
pub usingnamespace Group.Wasm;
|
||||||
|
pub usingnamespace GroupCache.Wasm;
|
||||||
pub usingnamespace face.web_canvas.Wasm;
|
pub usingnamespace face.web_canvas.Wasm;
|
||||||
} else struct {};
|
} else struct {};
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user