mirror of
https://github.com/ghostty-org/ghostty.git
synced 2025-04-20 00:18:53 +03:00
334 lines
13 KiB
Zig
334 lines
13 KiB
Zig
const std = @import("std");
|
|
const c = @import("c.zig").c;
|
|
const common = @import("common.zig");
|
|
const Error = @import("errors.zig").Error;
|
|
const Direction = common.Direction;
|
|
const Script = common.Script;
|
|
const Language = common.Language;
|
|
|
|
/// Buffers serve a dual role in HarfBuzz; before shaping, they hold the
|
|
/// input characters that are passed to hb_shape(), and after shaping they
|
|
/// hold the output glyphs.
|
|
pub const Buffer = struct {
|
|
handle: *c.hb_buffer_t,
|
|
|
|
/// Creates a new hb_buffer_t with all properties to defaults.
|
|
pub fn create() Error!Buffer {
|
|
const handle = c.hb_buffer_create() orelse return Error.HarfbuzzFailed;
|
|
return Buffer{ .handle = handle };
|
|
}
|
|
|
|
/// Deallocate the buffer . Decreases the reference count on buffer by one.
|
|
/// If the result is zero, then buffer and all associated resources are
|
|
/// freed. See hb_buffer_reference().
|
|
pub fn destroy(self: *Buffer) void {
|
|
c.hb_buffer_destroy(self.handle);
|
|
}
|
|
|
|
/// Resets the buffer to its initial status, as if it was just newly
|
|
/// created with hb_buffer_create().
|
|
pub fn reset(self: Buffer) void {
|
|
c.hb_buffer_reset(self.handle);
|
|
}
|
|
|
|
/// Returns the number of items in the buffer.
|
|
pub fn getLength(self: Buffer) u32 {
|
|
return c.hb_buffer_get_length(self.handle);
|
|
}
|
|
|
|
/// Sets the type of buffer contents. Buffers are either empty, contain
|
|
/// characters (before shaping), or contain glyphs (the result of shaping).
|
|
pub fn setContentType(self: Buffer, ct: ContentType) void {
|
|
c.hb_buffer_set_content_type(self.handle, @intFromEnum(ct));
|
|
}
|
|
|
|
/// Fetches the type of buffer contents. Buffers are either empty, contain
|
|
/// characters (before shaping), or contain glyphs (the result of shaping).
|
|
pub fn getContentType(self: Buffer) ContentType {
|
|
return @enumFromInt(c.hb_buffer_get_content_type(self.handle));
|
|
}
|
|
|
|
/// Appends a character with the Unicode value of codepoint to buffer,
|
|
/// and gives it the initial cluster value of cluster . Clusters can be
|
|
/// any thing the client wants, they are usually used to refer to the
|
|
/// index of the character in the input text stream and are output in
|
|
/// hb_glyph_info_t.cluster field.
|
|
///
|
|
/// This function does not check the validity of codepoint, it is up to
|
|
/// the caller to ensure it is a valid Unicode code point.
|
|
pub fn add(self: Buffer, cp: u32, cluster: u32) void {
|
|
c.hb_buffer_add(self.handle, cp, cluster);
|
|
}
|
|
|
|
/// Appends characters from text array to buffer . The item_offset is the
|
|
/// position of the first character from text that will be appended, and
|
|
/// item_length is the number of character. When shaping part of a larger
|
|
/// text (e.g. a run of text from a paragraph), instead of passing just
|
|
/// the substring corresponding to the run, it is preferable to pass the
|
|
/// whole paragraph and specify the run start and length as item_offset and
|
|
/// item_length , respectively, to give HarfBuzz the full context to be
|
|
/// able, for example, to do cross-run Arabic shaping or properly handle
|
|
/// combining marks at stat of run.
|
|
///
|
|
/// This function does not check the validity of text , it is up to the
|
|
/// caller to ensure it contains a valid Unicode code points.
|
|
pub fn addCodepoints(self: Buffer, text: []const u32) void {
|
|
c.hb_buffer_add_codepoints(
|
|
self.handle,
|
|
text.ptr,
|
|
@intCast(text.len),
|
|
0,
|
|
@intCast(text.len),
|
|
);
|
|
}
|
|
|
|
/// See hb_buffer_add_codepoints().
|
|
///
|
|
/// Replaces invalid UTF-32 characters with the buffer replacement code
|
|
/// point, see hb_buffer_set_replacement_codepoint().
|
|
pub fn addUTF32(self: Buffer, text: []const u32) void {
|
|
c.hb_buffer_add_utf32(
|
|
self.handle,
|
|
text.ptr,
|
|
@intCast(text.len),
|
|
0,
|
|
@intCast(text.len),
|
|
);
|
|
}
|
|
|
|
/// See hb_buffer_add_codepoints().
|
|
///
|
|
/// Replaces invalid UTF-16 characters with the buffer replacement code
|
|
/// point, see hb_buffer_set_replacement_codepoint().
|
|
pub fn addUTF16(self: Buffer, text: []const u16) void {
|
|
c.hb_buffer_add_utf16(
|
|
self.handle,
|
|
text.ptr,
|
|
@intCast(text.len),
|
|
0,
|
|
@intCast(text.len),
|
|
);
|
|
}
|
|
|
|
/// See hb_buffer_add_codepoints().
|
|
///
|
|
/// Replaces invalid UTF-8 characters with the buffer replacement code
|
|
/// point, see hb_buffer_set_replacement_codepoint().
|
|
pub fn addUTF8(self: Buffer, text: []const u8) void {
|
|
c.hb_buffer_add_utf8(
|
|
self.handle,
|
|
text.ptr,
|
|
@intCast(text.len),
|
|
0,
|
|
@intCast(text.len),
|
|
);
|
|
}
|
|
|
|
/// Similar to hb_buffer_add_codepoints(), but allows only access to first
|
|
/// 256 Unicode code points that can fit in 8-bit strings.
|
|
pub fn addLatin1(self: Buffer, text: []const u8) void {
|
|
c.hb_buffer_add_latin1(
|
|
self.handle,
|
|
text.ptr,
|
|
@intCast(text.len),
|
|
0,
|
|
@intCast(text.len),
|
|
);
|
|
}
|
|
|
|
/// Set the text flow direction of the buffer. No shaping can happen
|
|
/// without setting buffer direction, and it controls the visual direction
|
|
/// for the output glyphs; for RTL direction the glyphs will be reversed.
|
|
/// Many layout features depend on the proper setting of the direction,
|
|
/// for example, reversing RTL text before shaping, then shaping with LTR
|
|
/// direction is not the same as keeping the text in logical order and
|
|
/// shaping with RTL direction.
|
|
pub fn setDirection(self: Buffer, dir: Direction) void {
|
|
c.hb_buffer_set_direction(self.handle, @intFromEnum(dir));
|
|
}
|
|
|
|
/// See hb_buffer_set_direction()
|
|
pub fn getDirection(self: Buffer) Direction {
|
|
return @enumFromInt(c.hb_buffer_get_direction(self.handle));
|
|
}
|
|
|
|
/// Sets the script of buffer to script.
|
|
///
|
|
/// Script is crucial for choosing the proper shaping behaviour for
|
|
/// scripts that require it (e.g. Arabic) and the which OpenType features
|
|
/// defined in the font to be applied.
|
|
///
|
|
/// You can pass one of the predefined hb_script_t values, or use
|
|
/// hb_script_from_string() or hb_script_from_iso15924_tag() to get the
|
|
/// corresponding script from an ISO 15924 script tag.
|
|
pub fn setScript(self: Buffer, script: Script) void {
|
|
c.hb_buffer_set_script(self.handle, @intFromEnum(script));
|
|
}
|
|
|
|
/// See hb_buffer_set_script()
|
|
pub fn getScript(self: Buffer) Script {
|
|
return @enumFromInt(c.hb_buffer_get_script(self.handle));
|
|
}
|
|
|
|
/// Sets the language of buffer to language .
|
|
///
|
|
/// Languages are crucial for selecting which OpenType feature to apply to
|
|
/// the buffer which can result in applying language-specific behaviour.
|
|
/// Languages are orthogonal to the scripts, and though they are related,
|
|
/// they are different concepts and should not be confused with each other.
|
|
///
|
|
/// Use hb_language_from_string() to convert from BCP 47 language tags to
|
|
/// hb_language_t.
|
|
pub fn setLanguage(self: Buffer, language: Language) void {
|
|
c.hb_buffer_set_language(self.handle, language.handle);
|
|
}
|
|
|
|
/// See hb_buffer_set_language()
|
|
pub fn getLanguage(self: Buffer) Language {
|
|
return Language{ .handle = c.hb_buffer_get_language(self.handle) };
|
|
}
|
|
|
|
/// Returns buffer glyph information array. Returned pointer is valid as
|
|
/// long as buffer contents are not modified.
|
|
pub fn getGlyphInfos(self: Buffer) []GlyphInfo {
|
|
var length: u32 = 0;
|
|
const ptr: [*c]GlyphInfo = @ptrCast(c.hb_buffer_get_glyph_infos(self.handle, &length));
|
|
return ptr[0..length];
|
|
}
|
|
|
|
/// Returns buffer glyph position array. Returned pointer is valid as
|
|
/// long as buffer contents are not modified.
|
|
///
|
|
/// If buffer did not have positions before, the positions will be
|
|
/// initialized to zeros, unless this function is called from within a
|
|
/// buffer message callback (see hb_buffer_set_message_func()), in which
|
|
/// case NULL is returned.
|
|
pub fn getGlyphPositions(self: Buffer) ?[]GlyphPosition {
|
|
var length: u32 = 0;
|
|
|
|
if (c.hb_buffer_get_glyph_positions(self.handle, &length)) |positions| {
|
|
const ptr: [*]GlyphPosition = @ptrCast(positions);
|
|
return ptr[0..length];
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/// Sets unset buffer segment properties based on buffer Unicode contents.
|
|
/// If buffer is not empty, it must have content type
|
|
/// HB_BUFFER_CONTENT_TYPE_UNICODE.
|
|
///
|
|
/// If buffer script is not set (ie. is HB_SCRIPT_INVALID), it will be set
|
|
/// to the Unicode script of the first character in the buffer that has a
|
|
/// script other than HB_SCRIPT_COMMON, HB_SCRIPT_INHERITED, and
|
|
/// HB_SCRIPT_UNKNOWN.
|
|
///
|
|
/// Next, if buffer direction is not set (ie. is HB_DIRECTION_INVALID), it
|
|
/// will be set to the natural horizontal direction of the buffer script as
|
|
/// returned by hb_script_get_horizontal_direction(). If
|
|
/// hb_script_get_horizontal_direction() returns HB_DIRECTION_INVALID,
|
|
/// then HB_DIRECTION_LTR is used.
|
|
///
|
|
/// Finally, if buffer language is not set (ie. is HB_LANGUAGE_INVALID), it
|
|
/// will be set to the process's default language as returned by
|
|
/// hb_language_get_default(). This may change in the future by taking
|
|
/// buffer script into consideration when choosing a language. Note that
|
|
/// hb_language_get_default() is NOT threadsafe the first time it is
|
|
/// called. See documentation for that function for details.
|
|
pub fn guessSegmentProperties(self: Buffer) void {
|
|
c.hb_buffer_guess_segment_properties(self.handle);
|
|
}
|
|
};
|
|
|
|
/// The type of hb_buffer_t contents.
|
|
pub const ContentType = enum(u2) {
|
|
/// Initial value for new buffer.
|
|
invalid = c.HB_BUFFER_CONTENT_TYPE_INVALID,
|
|
|
|
/// The buffer contains input characters (before shaping).
|
|
unicode = c.HB_BUFFER_CONTENT_TYPE_UNICODE,
|
|
|
|
/// The buffer contains output glyphs (after shaping).
|
|
glyphs = c.HB_BUFFER_CONTENT_TYPE_GLYPHS,
|
|
};
|
|
|
|
/// The hb_glyph_info_t is the structure that holds information about the
|
|
/// glyphs and their relation to input text.
|
|
pub const GlyphInfo = extern struct {
|
|
/// either a Unicode code point (before shaping) or a glyph index (after shaping).
|
|
codepoint: u32,
|
|
_mask: u32,
|
|
|
|
/// the index of the character in the original text that corresponds to
|
|
/// this hb_glyph_info_t, or whatever the client passes to hb_buffer_add().
|
|
/// More than one hb_glyph_info_t can have the same cluster value, if they
|
|
/// resulted from the same character (e.g. one to many glyph substitution),
|
|
/// and when more than one character gets merged in the same glyph (e.g.
|
|
/// many to one glyph substitution) the hb_glyph_info_t will have the
|
|
/// smallest cluster value of them. By default some characters are merged
|
|
/// into the same cluster (e.g. combining marks have the same cluster as
|
|
/// their bases) even if they are separate glyphs, hb_buffer_set_cluster_level()
|
|
/// allow selecting more fine-grained cluster handling.
|
|
cluster: u32,
|
|
_var1: u32,
|
|
_var2: u32,
|
|
};
|
|
|
|
/// The hb_glyph_position_t is the structure that holds the positions of the
|
|
/// glyph in both horizontal and vertical directions. All positions in
|
|
/// hb_glyph_position_t are relative to the current point.
|
|
pub const GlyphPosition = extern struct {
|
|
/// how much the line advances after drawing this glyph when setting text
|
|
/// in horizontal direction.
|
|
x_advance: i32,
|
|
|
|
/// how much the line advances after drawing this glyph when setting text
|
|
/// in vertical direction.
|
|
y_advance: i32,
|
|
|
|
/// how much the glyph moves on the X-axis before drawing it, this should
|
|
/// not affect how much the line advances.
|
|
x_offset: i32,
|
|
|
|
/// how much the glyph moves on the Y-axis before drawing it, this should
|
|
/// not affect how much the line advances.
|
|
y_offset: i32,
|
|
|
|
_var: u32,
|
|
};
|
|
|
|
test "create" {
|
|
const testing = std.testing;
|
|
|
|
var buffer = try Buffer.create();
|
|
defer buffer.destroy();
|
|
buffer.reset();
|
|
|
|
// Content type
|
|
buffer.setContentType(.unicode);
|
|
try testing.expectEqual(ContentType.unicode, buffer.getContentType());
|
|
|
|
// Try add functions
|
|
buffer.add('🥹', 27);
|
|
var utf32 = [_]u32{ 'A', 'B', 'C' };
|
|
var utf16 = [_]u16{ 'A', 'B', 'C' };
|
|
var utf8 = [_]u8{ 'A', 'B', 'C' };
|
|
buffer.addCodepoints(&utf32);
|
|
buffer.addUTF32(&utf32);
|
|
buffer.addUTF16(&utf16);
|
|
buffer.addUTF8(&utf8);
|
|
buffer.addLatin1(&utf8);
|
|
|
|
// Guess properties first
|
|
buffer.guessSegmentProperties();
|
|
|
|
// Try to set properties
|
|
buffer.setDirection(.ltr);
|
|
try testing.expectEqual(Direction.ltr, buffer.getDirection());
|
|
|
|
buffer.setScript(.arabic);
|
|
try testing.expectEqual(Script.arabic, buffer.getScript());
|
|
|
|
buffer.setLanguage(Language.fromString("en"));
|
|
}
|