font/freetype: synthetic italic

This commit is contained in:
Mitchell Hashimoto
2024-08-24 20:51:26 -07:00
parent 022e554cf1
commit 5f0daa23b9
2 changed files with 55 additions and 1 deletions

View File

@ -14,6 +14,11 @@ pub const Face = struct {
_ = c.FT_Done_Face(self.handle);
}
/// Increment the counter of the face.
pub fn ref(self: Face) void {
_ = c.FT_Reference_Face(self.handle);
}
/// A macro that returns true whenever a face object contains some
/// embedded bitmaps. See the available_sizes field of the FT_FaceRec structure.
pub fn hasFixedSizes(self: Face) bool {
@ -170,6 +175,20 @@ pub const Face = struct {
);
return intToError(res);
}
/// Set the transformation that is applied to glyph images when they are
/// loaded into a glyph slot through FT_Load_Glyph.
pub fn setTransform(
self: Face,
matrix: ?*const c.FT_Matrix,
delta: ?*const c.FT_Vector,
) void {
c.FT_Set_Transform(
self.handle,
@constCast(@ptrCast(matrix)),
@constCast(@ptrCast(delta)),
);
}
};
/// An enumeration to specify indices of SFNT tables loaded and parsed by

View File

@ -37,6 +37,17 @@ pub const Face = struct {
/// Set quirks.disableDefaultFontFeatures
quirks_disable_default_font_features: bool = false,
/// Set to true to apply a synthetic italic to the face.
synthetic_italic: bool = false,
/// The matrix applied to a regular font to create a synthetic italic.
const italic_matrix: freetype.c.FT_Matrix = .{
.xx = 0x10000,
.xy = 0x044ED, // approx. tan(15)
.yx = 0,
.yy = 0x10000,
};
/// 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 {
const face = try lib.lib.initFace(path, index);
@ -119,6 +130,24 @@ pub const Face = struct {
return "";
}
/// Return a new face that is the same as this but has a transformation
/// matrix applied to italicize it.
pub fn syntheticItalic(self: *const Face, opts: font.face.Options) !Face {
// Increase face ref count
self.face.ref();
errdefer self.face.deinit();
var f = try initFace(
.{ .lib = self.lib },
self.face,
opts,
);
errdefer f.deinit();
f.synthetic_italic = true;
return f;
}
/// Resize the font in-place. If this succeeds, the caller is responsible
/// for clearing any glyph caches, font atlas data, etc.
pub fn setSize(self: *Face, opts: font.face.Options) !void {
@ -246,6 +275,12 @@ pub const Face = struct {
) !Glyph {
const metrics = opts.grid_metrics orelse self.metrics;
// If we have synthetic italic, then we apply a transformation matrix.
// We have to undo this because synthetic italic works by increasing
// the ref count of the base face.
if (self.synthetic_italic) self.face.setTransform(&italic_matrix, null);
defer if (self.synthetic_italic) self.face.setTransform(null, null);
// If our glyph has color, we want to render the color
try self.face.loadGlyph(glyph_index, .{
.render = true,
@ -265,7 +300,7 @@ pub const Face = struct {
// This bitmap is blank. I've seen it happen in a font, I don't know why.
// If it is empty, we just return a valid glyph struct that does nothing.
if (bitmap_ft.rows == 0) return Glyph{
if (bitmap_ft.rows == 0) return .{
.width = 0,
.height = 0,
.offset_x = 0,