init
Load the underlying font at an integer size <= font.size (guaranteed to have a minimum pixel size of 1)
Parameters
- gpa:std.mem.Allocator
- std.mem.Allocator
- ttf_bytes:[]const u8
- []const u8
- font:Font
- Font
Source
Implementation
pub fn init(gpa: std.mem.Allocator, ttf_bytes: []const u8, font: Font) Error!Entry {
const min_pixel_size = 1;
const fname = font.name(gpa);
errdefer gpa.free(fname);
var self: Entry = if (impl == .FreeType) blk: {
var face: c.FT_Face = undefined;
var args: c.FT_Open_Args = undefined;
args.flags = @as(u32, @bitCast(FreeType.OpenFlags{ .memory = true }));
args.memory_base = ttf_bytes.ptr;
args.memory_size = @as(u31, @intCast(ttf_bytes.len));
FreeType.intToError(c.FT_Open_Face(dvui.ft2lib, &args, 0, &face)) catch |err| {
dvui.log.warn("Font.Cache.Entry.init() freetype error {any} trying to FT_Open_Face font {s}\n", .{ err, fname });
return Error.FontError;
};
// "pixel size" for freetype doesn't actually mean you'll get that height, it's more like using pts
// so we search for a font that has a height <= font.size
var pixel_size = @as(u32, @trunc(@max(min_pixel_size, @floor(font.size))));
pixel_size += 20;
while (true) : (pixel_size -= 1) {
FreeType.intToError(c.FT_Set_Pixel_Sizes(face, pixel_size, pixel_size)) catch |err| {
dvui.log.warn("Font.Cache.Entry.init() freetype error {any} trying to FT_Set_Pixel_Sizes font {s}\n", .{ err, fname });
return Error.FontError;
};
const ascender = @as(f32, @floatFromInt(face.*.ascender)) / 64.0;
const ss = @as(f32, @floatFromInt(face.*.size.*.metrics.y_scale)) / 0x10000;
const fascent = ascender * ss;
const descender = @as(f32, @floatFromInt(face.*.descender)) / 64.0;
const descent = descender * ss;
var entry: Entry = .{
.face = face,
.name = fname,
.scaleFactor = 1.0, // not used with freetype
.height = fascent - descent,
.ascent = @trunc(fascent), // cheat ascent a bit, must be an integer
.em_height = undefined, // below
.glyph_info_ascii = undefined,
};
const M = try entry.glyphInfoGenerate('M');
if (M.h <= 0) {
dvui.log.warn("Font.Cache.Entry.init() freetype error getting M font {s} size {d}\n", .{ fname, font.size });
return error.FontError;
}
if (M.h <= font.size or pixel_size == min_pixel_size) {
//std.debug.print("{s} pixel_size {d} ascent {d} descent {d} height {d}\n", .{fname, pixel_size, ascent, descent, ascent - descent});
entry.em_height = M.h;
break :blk entry;
}
}
} else blk: {
const offset = c.stbtt_GetFontOffsetForIndex(ttf_bytes.ptr, 0);
if (offset < 0) {
dvui.log.warn("Font.Cache.Entry.init() stbtt error when calling stbtt_GetFontOffsetForIndex font {s}\n", .{fname});
return Error.FontError;
}
var face: c.stbtt_fontinfo = undefined;
if (c.stbtt_InitFont(&face, ttf_bytes.ptr, offset) != 1) {
dvui.log.warn("Font.Cache.Entry.init() stbtt error when calling stbtt_InitFont font {s}\n", .{fname});
return Error.FontError;
}
var face_ascent: c_int = undefined;
var face_descent: c_int = undefined;
c.stbtt_GetFontVMetrics(&face, &face_ascent, &face_descent, null);
var entry: Entry = .{
.face = face,
.name = fname,
.scaleFactor = 1.0, // adjusted below
.height = 1.0, // adjusted below
.ascent = 1.0, // adjusted below
.em_height = undefined, // below
.glyph_info_ascii = undefined,
};
const M = try entry.glyphInfoGenerate('M');
if (M.h <= 0) {
dvui.log.warn("Font.Cache.Entry.init() stbtt error getting M font {s} size {d}\n", .{ fname, font.size });
return error.FontError;
}
entry.scaleFactor = @max(min_pixel_size, @floor(font.size)) / M.h;
const ascender = entry.scaleFactor * @as(f32, @floatFromInt(face_ascent));
const descender = entry.scaleFactor * @as(f32, @floatFromInt(face_descent));
entry.ascent = @trunc(ascender); // cheat the ascent a bit, must be integer
entry.height = ascender - descender;
entry.em_height = entry.scaleFactor * M.h;
//std.debug.print("{s} ascent {d} descent {d} computed ascent {d} height {d}\n", .{fname, ascender, descender, entry.ascent, entry.height});
break :blk entry;
};
// Pre-generate the ascii glyphs
//std.debug.print("char,codepoint,hx,w,hy,h,adv\n", .{});
for (0..self.glyph_info_ascii.len) |i| {
self.glyph_info_ascii[i] = try self.glyphInfoGenerate(@intCast(i + ascii_start));
}
//const gi = self.glyph_info_ascii['M' - ascii_start];
//std.debug.print("{s} size {d} height {d} M left {d} top {d} wxh {d}x{d}\n", .{ fname, font.size, self.height, gi.leftBearing, gi.topBearing, gi.w, gi.h});
return self;
}