// SPDX-FileCopyrightText: © 2026 Jeffrey C. Ollie // SPDX-License-Identifier: MIT //! An OpenType text shaper: given text and a font decoded by zig-font, it //! picks the glyphs and works out where each goes, applying the font's //! `GSUB` and `GPOS` features as HarfBuzz does. //! //! ```zig //! var face: shaper.Face = .init(gpa, &font, &.{}); //! var buffer: shaper.Buffer = .init(gpa); //! defer buffer.deinit(); //! try buffer.addUtf8("Hello", 0, null); //! buffer.guessSegmentProperties(); //! try shaper.shapeBuffer(gpa, &face, &buffer, &.{}); //! for (buffer.info.items, buffer.pos.items) |info, pos| { //! // info.codepoint is the glyph ID, info.cluster the text it came //! // from, and pos its advance and offset in font units. //! } //! ``` //! //! The pipeline is a port of HarfBuzz's OpenType shaper, kept close enough //! to the original that it gives the same glyphs and positions, which the //! test suite checks against HarfBuzz's own tests. It has HarfBuzz's default //! shaper and its Arabic one; scripts that HarfBuzz gives a shaper of their //! own (Indic, Khmer, Myanmar, Hangul, Thai, Hebrew and the Universal Shaping //! Engine scripts) are shaped with the default one for now. const std = @import("std"); pub const Buffer = @import("Buffer.zig"); pub const Face = @import("Face.zig"); pub const Feature = @import("Feature.zig"); pub const Map = @import("Map.zig"); pub const shape = @import("shape.zig"); pub const unicode = @import("unicode.zig"); pub const script = @import("script.zig"); pub const language = @import("language.zig"); pub const variations = @import("variations.zig"); pub const Plan = shape.Plan; pub const Direction = script.Direction; pub const Script = script.Script; pub const Language = language.Language; pub const GlyphInfo = Buffer.GlyphInfo; pub const GlyphPosition = Buffer.GlyphPosition; /// Shapes `buffer` with a plan made for it on the spot. The buffer's /// direction must be set; `Buffer.guessSegmentProperties` sets it, and the /// script, from the text. To shape many runs alike, make a `Plan` once and /// call `shape.shape` with it instead. pub fn shapeBuffer(gpa: std.mem.Allocator, face: *const Face, buffer: *Buffer, features: []const Feature) std.mem.Allocator.Error!void { var plan: Plan = try .init(gpa, face, .{ .direction = buffer.direction orelse .ltr, .script = buffer.script, .language = buffer.language, .features = features, }); defer plan.deinit(); try shape.shape(&plan, buffer); } test { _ = Buffer; _ = Face; _ = Feature; _ = Map; _ = shape; _ = unicode; _ = script; _ = language; _ = variations; _ = @import("cmap.zig"); _ = @import("round.zig"); _ = @import("apply.zig"); _ = @import("gsub.zig"); _ = @import("gpos.zig"); _ = @import("normalize.zig"); _ = @import("fallback.zig"); _ = @import("kern.zig"); _ = @import("props.zig"); _ = @import("shapers/arabic.zig"); _ = @import("shapers/indic.zig"); _ = @import("shapers/khmer.zig"); _ = @import("shapers/myanmar.zig"); _ = @import("shapers/use.zig"); _ = @import("shapers/hangul.zig"); _ = @import("shapers/hebrew.zig"); _ = @import("shapers/thai.zig"); _ = @import("shapers/ragel.zig"); _ = @import("shapers/syllabic.zig"); }