diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5c66e4e..f8465b4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,7 +18,7 @@ jobs: steps: - name: Install Harfbuzz - run: sudo apt-get install libharfbuzz0b libharfbuzz-dev + run: sudo apt-get install libharfbuzz0b libharfbuzz-dev libharfbuzz-subset0 - uses: actions/checkout@master diff --git a/.gitignore b/.gitignore index b2dffea..4ac27c3 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ luacov.stats.out .luacheckcache api *.src.rock +docs \ No newline at end of file diff --git a/config.ld b/config.ld index 5646b5c..9a7f6e4 100644 --- a/config.ld +++ b/config.ld @@ -1,9 +1,9 @@ project = 'luaharfbuzz' description = 'Lua bindings to Harfbuzz' -full_description = 'The documentation is available on the @{https://github.com/harfbuzz/luaharfbuzz/wiki|wiki}' +full_description = 'The documentation is available at https://github.com/harfbuzz/luaharfbuzz/wiki' use_markdown_titles = true backtick_references = false title = 'luaharfbuzz Documentation' -file = 'src/harfbuzz.luadoc' +file = {'src/harfbuzz.luadoc', 'src/harfbuzz-subset.luadoc'} examples = 'examples' format = 'markdown' diff --git a/fonts/AdventPro-VariableFont_wdth,wght.ttf b/fonts/AdventPro-VariableFont_wdth,wght.ttf new file mode 100644 index 0000000..cbc3a33 Binary files /dev/null and b/fonts/AdventPro-VariableFont_wdth,wght.ttf differ diff --git a/luaharfbuzz-scm-1.rockspec b/luaharfbuzz-scm-1.rockspec index ba87726..32f2466 100644 --- a/luaharfbuzz-scm-1.rockspec +++ b/luaharfbuzz-scm-1.rockspec @@ -4,6 +4,9 @@ version = "scm-1" source = { url = "git://github.com/harfbuzz/luaharfbuzz" } +dependencies = { + "lua >= 5.3" +} description = { summary = "Lua bindings for the Harfbuzz text shaping library", homepage = "https://github.com/harfbuzz/luaharfbuzz", @@ -12,33 +15,41 @@ description = { issues_url = "https://github.com/harfbuzz/luaharfbuzz/issues", labels = {"unicode", "fonts"} } -dependencies = { - "lua >= 5.3" -} build = { type = "builtin", modules = { harfbuzz ="src/harfbuzz.lua", luaharfbuzz= { sources = { - "src/luaharfbuzz/luaharfbuzz.c", - "src/luaharfbuzz/blob.c", - "src/luaharfbuzz/face.c", - "src/luaharfbuzz/font.c", - "src/luaharfbuzz/buffer.c", - "src/luaharfbuzz/feature.c", - "src/luaharfbuzz/tag.c", - "src/luaharfbuzz/ot.c", - "src/luaharfbuzz/unicode.c", - "src/luaharfbuzz/script.c", - "src/luaharfbuzz/direction.c", - "src/luaharfbuzz/language.c", - "src/luaharfbuzz/variation.c", - "src/luaharfbuzz/class_utils.c" + "src/luaharfbuzz/luaharfbuzz.c", + "src/luaharfbuzz/blob.c", + "src/luaharfbuzz/face.c", + "src/luaharfbuzz/font.c", + "src/luaharfbuzz/buffer.c", + "src/luaharfbuzz/feature.c", + "src/luaharfbuzz/tag.c", + "src/luaharfbuzz/ot.c", + "src/luaharfbuzz/unicode.c", + "src/luaharfbuzz/set.c", + "src/luaharfbuzz/script.c", + "src/luaharfbuzz/direction.c", + "src/luaharfbuzz/language.c", + "src/luaharfbuzz/variation.c", + "src/class_utils.c", }, libraries = {"harfbuzz"}, incdirs = {"$(HARFBUZZ_INCDIR)/harfbuzz"}, libdirs = {"$(HARFBUZZ_LIBDIR)"} + }, + luaharfbuzzsubset = { + sources = { + "src/luaharfbuzzsubset/luaharfbuzzsubset.c", + "src/luaharfbuzzsubset/subset-input.c", + "src/class_utils.c", + }, + libraries = {"harfbuzz-subset"}, + incdirs = {"$(HARFBUZZ_INCDIR)/harfbuzz"}, + libdirs = {"$(HARFBUZZ_LIBDIR)"} } } } diff --git a/spec/subset_spec.lua b/spec/subset_spec.lua new file mode 100644 index 0000000..ed0133f --- /dev/null +++ b/spec/subset_spec.lua @@ -0,0 +1,143 @@ +package.path = "./src/?.lua;./src/?/init.lua;" .. package.path + +local harfbuzzsubset = require("harfbuzzsubset") +local harfbuzz = require("harfbuzz") + +describe("harfbuzz module", function() + it("can be required when subset module is also required", function() + assert.is_not_nil(harfbuzz) + assert.is_not_nil(harfbuzzsubset) + end) +end) + + +describe("harfbuzzsubset basic usage", function() + local hb, hb_subset + local font_path = "fonts/AdventPro-VariableFont_wdth,wght.ttf" + + setup(function() + hb = require "harfbuzz" + hb_subset = require "harfbuzzsubset" + end) + + it("returns a valid version string", function() + assert.are_equal("string", type(hb_subset.version())) + end) + + it("creates a subset input object", function() + local input = hb_subset.subset_input.new() + assert.truthy(input) + -- minimal test of methods existing + assert.is_function(input.keep_everything) + assert.is_function(input.pin_axis_location) + end) + + it("can subset a variable font without errors", function() + local face = hb.Face.new(font_path) + local wght = hb.Tag.new("wght") + local wdth = hb.Tag.new("wdth") + + local input = hb_subset.subset_input.new() + input:pin_axis_location(face, wght, 100) + input:pin_axis_location(face, wdth, 100) + input:keep_everything() + + local ok, new_face = pcall(function() + return hb_subset.subset(face, input) + end) + + assert.is_true(ok) + assert.truthy(new_face) + assert.are_not.equal(face, new_face) + end) + + it("produces a non-empty blob after subsetting", function() + local face = hb.Face.new(font_path) + local wght = hb.Tag.new("wght") + local wdth = hb.Tag.new("wdth") + + local input = hb_subset.subset_input.new() + input:pin_axis_location(face, wght, 100) + input:pin_axis_location(face, wdth, 100) + input:keep_everything() + + local new_face = hb_subset.subset(face, input) + + local blob = new_face:blob() + assert.truthy(blob) + assert.is_function(blob.get_data) + + local data = blob:get_data() + assert.is_string(data) + assert.is_true(#data > 0) + end) + + it("preserves glyph count when keep_everything is used", function() + local face = hb.Face.new(font_path) + local orig_glyphs = face:get_glyph_count() + + local wght = hb.Tag.new("wght") + local wdth = hb.Tag.new("wdth") + local input = hb_subset.subset_input.new() + input:pin_axis_location(face, wght, 100) + input:pin_axis_location(face, wdth, 100) + input:keep_everything() + + local new_face = hb_subset.subset(face, input) + local subset_glyphs = new_face:get_glyph_count() + + assert.equals(orig_glyphs, subset_glyphs) + end) + + it("produces different blobs for different axis locations", function() + local face = hb.Face.new(font_path) + local wght = hb.Tag.new("wght") + local wdth = hb.Tag.new("wdth") + + local input1 = hb_subset.subset_input.new() + input1:pin_axis_location(face, wght, 100) + input1:pin_axis_location(face, wdth, 100) + input1:keep_everything() + local face_light = hb_subset.subset(face, input1) + local blob_light = face_light:blob():get_data() + + local input2 = hb_subset.subset_input.new() + input2:pin_axis_location(face, wght, 900) + input2:pin_axis_location(face, wdth, 100) + input2:keep_everything() + local face_bold = hb_subset.subset(face, input2) + local blob_bold = face_bold:blob():get_data() + + assert.is_true( + blob_light ~= blob_bold, + ("expected different blobs for axis locations, but they are identical (len=%d bytes)") + :format(#blob_light) + ) + assert.is_true(#blob_light > 0, "blob_light is empty") + assert.is_true(#blob_bold > 0, "blob_bold is empty") + end) + + it("reduces glyph count when subsetting to a single Unicode", function() + local face = hb.Face.new(font_path) + local orig_glyphs = face:get_glyph_count() + + local input = hb_subset.subset_input.new() + + local uset = input:unicode_set() + uset:add(0x41) -- oder string.byte("A") + + local new_face = hb_subset.subset(face, input) + local subset_glyphs = new_face:get_glyph_count() + + -- Sanity-Checks mit vernünftiger Fehlermeldung, ohne Binärmüll: + assert.is_true( + subset_glyphs > 0, + ("expected subset glyph count > 0, got %d"):format(subset_glyphs) + ) + assert.is_true( + subset_glyphs < orig_glyphs, + ("expected fewer glyphs after subsetting, got %d (orig %d)") + :format(subset_glyphs, orig_glyphs) + ) + end) +end) diff --git a/src/luaharfbuzz/class_utils.c b/src/class_utils.c similarity index 96% rename from src/luaharfbuzz/class_utils.c rename to src/class_utils.c index 9851ce4..750ad4f 100644 --- a/src/luaharfbuzz/class_utils.c +++ b/src/class_utils.c @@ -1,5 +1,5 @@ // Utility functions to create Lua classes. -#include "luaharfbuzz.h" +#include "common.h" int register_class(lua_State *L, const char *name, const luaL_Reg *methods, const luaL_Reg *functions, const luahb_constant_t *constants) { luaL_newmetatable(L, name); diff --git a/src/common.h b/src/common.h new file mode 100644 index 0000000..55ef28d --- /dev/null +++ b/src/common.h @@ -0,0 +1,30 @@ +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +typedef hb_blob_t* Blob; +typedef hb_face_t* Face; +typedef hb_font_t* Font; +typedef hb_buffer_t* Buffer; +typedef hb_set_t* Set; +typedef hb_feature_t Feature; +typedef hb_tag_t Tag; +typedef hb_script_t Script; +typedef hb_direction_t Direction; +typedef hb_language_t Language; +typedef hb_variation_t Variation; + +typedef struct luahb_constant_t { + const char *name; + int value; +} luahb_constant_t; + +// Functions to create classes and push them onto the stack +int register_class(lua_State *L, const char *name, const luaL_Reg * methods, const luaL_Reg *functions, const luahb_constant_t* constants); diff --git a/src/harfbuzz-subset.luadoc b/src/harfbuzz-subset.luadoc new file mode 100644 index 0000000..4ac2020 --- /dev/null +++ b/src/harfbuzz-subset.luadoc @@ -0,0 +1,111 @@ +----------- +-- Lua bindings to the Harfbuzz subset API. +-- * [Wiki](http://github.com/harfbuzz/luaharfbuzz/wiki) +-- * [Source on Github](https://github.com/harfbuzz/luaharfbuzz) +-- * [API Coverage Status](https://github.com/harfbuzz/luaharfbuzz/blob/master/status/done.txt) +-- +-- This module provides bindings to the HarfBuzz `hb-subset` API. It is +-- designed to be used together with the main @{harfbuzz} module. +-- +-- Typical usage: +-- +-- local hb = require('harfbuzz') +-- local hb_subset = require("harfbuzzsubset") +-- +-- local input = hb_subset.subset.create() +-- +-- local wght = hb.Tag.new("wght") +-- local wdth = hb.Tag.new("wdth") +-- local face = hb.Face.new("myfont.ttf") +-- +-- input:pin_axis_location(face,wght, 100) +-- input:pin_axis_location(face,wdth, 100) +-- +-- input:keep_everything() +-- new_face = hb_subset.subset(face, input) +-- +-- local blob = new_face:blob() +-- local fh, err = io.open("out.ttf", "wb") +-- if not fh then error(err) end +-- fh:write(blob:get_data()) +-- fh:close() +-- +-- The module returned by `require "harfbuzzsubset"` has two fields: +-- +-- * `subset_input` — helpers and methods related to @{SubsetInput} +-- * `subset` — helpers and methods related to @{SubsetInput} +-- +-- @author Patrick Gundlach <> +-- @copyright 2025 +-- @license MIT +-- @module harfbuzzsubset + + +--- Wraps `hb_subset_or_fail`. +-- +-- Performs the actual subset operation, producing a new `Face` that only +-- contains the glyphs and data configured on this input. +-- +-- @param face source `Face` object to subset. +-- @param input `SubsetInput` object to subset based on. +-- @return new `Face` object representing the subset, or `nil` on failure. +-- @function subset + + +--- Wraps `hb_version`. +-- @function version + +--- Lua wrapper for `hb_subset_input_t` type. +-- +-- Objects of this type control which parts of a `Face` are kept when +-- creating a subset. +-- +-- Instances are usually created via @{subset_input.new}. +-- +-- @type SubsetInput + + +--- Wraps `hb_subset_input_create_or_fail`. +-- +-- Initializes a new `hb_subset_input_t`. The returned object can be used to +-- configure which glyphs and features are kept when subsetting a face. +-- +-- @return `SubsetInput` object, or `nil` on failure. +-- @function subset_input.new + + +--- Wraps `hb_subset_input_unicode_set`. +-- +-- Returns the Unicode set associated with this subset input. The returned +-- @{harfbuzz.Set} can be modified (e.g. via @{harfbuzz.Set:add}) to control which +-- Unicode codepoints are included in the subset. +-- +-- @return `Set` object representing the Unicode set, or `nil` on failure. +-- @function SubsetInput:unicode_set + + +--- Wraps `hb_subset_input_pin_axis_location`. +-- +-- Pins a variation axis at a specific value for subsetting. +-- +-- @param face `Face` object whose design space is being subset. +-- @param tag `Tag` object representing the axis tag (e.g. `"wght"`, `"wdth"`). +-- @param value numeric axis value to pin. +-- @return `true` on success, `false` on failure. +-- @function SubsetInput:pin_axis_location + + +--- Wraps `hb_subset_input_keep_everything`. +-- +-- Configures the input so that everything in the original face is kept. +-- This is useful as a starting point before applying more specific filters. +-- +-- @function SubsetInput:keep_everything + + +--- Wraps `hb_subset_input_destroy`. +-- +-- Destructor for subset inputs. Normally this is invoked automatically by +-- the garbage collector; applications rarely need to call it directly. +-- +-- @function SubsetInput:__gc diff --git a/src/harfbuzz.luadoc b/src/harfbuzz.luadoc index a51be5f..5c65687 100644 --- a/src/harfbuzz.luadoc +++ b/src/harfbuzz.luadoc @@ -9,7 +9,7 @@ -- @license MIT -- @module harfbuzz ---- Wraps `hb_version` +--- Wraps `hb_version`. -- @function version --- Wraps `hb_shape`. @@ -533,3 +533,17 @@ --- Wraps `HB_OT_LAYOUT_NO_VARIATIONS_INDEX` -- @field ot.LAYOUT_NO_VARIATIONS_INDEX + + +--- Lua wrapper for `hb_set_t` type. +-- +-- Set objects represent a mathematical set of integer values. +-- +-- @type Set + +--- Wraps `hb_set_add`. +-- +-- Adds a codepoint to the set. +-- +-- @param codepoint The element to add. +-- @function Set:add diff --git a/src/harfbuzzsubset.lua b/src/harfbuzzsubset.lua new file mode 100644 index 0000000..38fcc39 --- /dev/null +++ b/src/harfbuzzsubset.lua @@ -0,0 +1,3 @@ +local hb = require("luaharfbuzzsubset") + +return hb diff --git a/src/luaharfbuzz/blob.c b/src/luaharfbuzz/blob.c index 889f5b1..d40dc5e 100644 --- a/src/luaharfbuzz/blob.c +++ b/src/luaharfbuzz/blob.c @@ -13,6 +13,13 @@ static int blob_new(lua_State *L) { return 1; } +static int blob_destroy(lua_State *L) { + Blob *b = (Blob *)luaL_checkudata(L, 1, "harfbuzz.Blob"); + + hb_blob_destroy(*b); + return 0; +} + static int blob_new_from_file(lua_State *L) { Blob *b; const char *file_name = luaL_checkstring(L, 1); @@ -44,6 +51,7 @@ static int blob_get_data(lua_State *L) { } static const struct luaL_Reg blob_methods[] = { + { "__gc", blob_destroy }, { "get_length", blob_get_length }, { "get_data", blob_get_data }, { NULL, NULL } diff --git a/src/luaharfbuzz/face.c b/src/luaharfbuzz/face.c index d7f8820..d6c4fe8 100644 --- a/src/luaharfbuzz/face.c +++ b/src/luaharfbuzz/face.c @@ -596,6 +596,26 @@ static int face_var_normalize_coords(lua_State *L) { return count; } +// face_blob(face) -> harfbuzz.Blob|nil, err +// Returns the underlying face blob as a harfbuzz.Blob userdata. +static int face_blob(lua_State *L) { + Face *f = (Face *)luaL_checkudata(L, 1, "harfbuzz.Face"); + + hb_blob_t *hb = hb_face_reference_blob(*f); + if (!hb) { + lua_pushnil(L); + return 1; + } + + // Create Blob userdata and attach the HarfBuzz blob without copying. + Blob *b = (Blob *)lua_newuserdata(L, sizeof(*b)); + luaL_getmetatable(L, "harfbuzz.Blob"); + lua_setmetatable(L, -2); + + *b = hb; + return 1; +} + static int face_destroy(lua_State *L) { Face *f = (Face *)luaL_checkudata(L, 1, "harfbuzz.Face"); @@ -605,6 +625,7 @@ static int face_destroy(lua_State *L) { static const struct luaL_Reg face_methods[] = { { "__gc", face_destroy }, + { "blob", face_blob }, { "collect_unicodes", face_collect_unicodes }, { "get_glyph_count", face_get_glyph_count }, { "get_name", face_get_name }, diff --git a/src/luaharfbuzz/luaharfbuzz.c b/src/luaharfbuzz/luaharfbuzz.c index 9c25655..21f7126 100644 --- a/src/luaharfbuzz/luaharfbuzz.c +++ b/src/luaharfbuzz/luaharfbuzz.c @@ -98,6 +98,9 @@ int luaopen_luaharfbuzz (lua_State *L) { register_unicode(L); lua_setfield(L, -2, "unicode"); + register_set(L); + lua_setfield(L, -2, "set"); + luaL_setfuncs(L, lib_table, 0); return 1; diff --git a/src/luaharfbuzz/luaharfbuzz.h b/src/luaharfbuzz/luaharfbuzz.h index 7c68d96..03e6869 100644 --- a/src/luaharfbuzz/luaharfbuzz.h +++ b/src/luaharfbuzz/luaharfbuzz.h @@ -1,32 +1,6 @@ -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -typedef hb_blob_t* Blob; -typedef hb_face_t* Face; -typedef hb_font_t* Font; -typedef hb_buffer_t* Buffer; -typedef hb_feature_t Feature; -typedef hb_tag_t Tag; -typedef hb_script_t Script; -typedef hb_direction_t Direction; -typedef hb_language_t Language; -typedef hb_variation_t Variation; - -typedef struct luahb_constant_t { - const char *name; - int value; -} luahb_constant_t; +#include "../common.h" // Functions to create classes and push them onto the stack -int register_class(lua_State *L, const char *name, const luaL_Reg * methods, const luaL_Reg *functions, const luahb_constant_t* constants); int register_blob(lua_State *L); int register_face(lua_State *L); int register_font(lua_State *L); @@ -39,3 +13,4 @@ int register_language(lua_State *L); int register_variation(lua_State *L); int register_ot(lua_State *L); int register_unicode(lua_State *L); +int register_set(lua_State *L); diff --git a/src/luaharfbuzz/set.c b/src/luaharfbuzz/set.c new file mode 100644 index 0000000..6e12642 --- /dev/null +++ b/src/luaharfbuzz/set.c @@ -0,0 +1,24 @@ +#include "luaharfbuzz.h" + +// implement hb_set_add for unicode +static int subset_set_add(lua_State *L) { + Set *set = (Set *)luaL_checkudata(L, 1, "harfbuzz.Set"); + unsigned int codepoint = (unsigned int)luaL_checkinteger(L, 2); + hb_set_add(*set, codepoint); + return 0; +} + +static const struct luaL_Reg set_methods[] = { + {"add", subset_set_add}, + {NULL, NULL} +}; + +// register the set method add +static const luaL_Reg set_functions[] = { + {NULL, NULL} +}; + +// register the namespace "harfbuzz.Set" and associate ith with the set_methods +int register_set(lua_State *L) { + return register_class(L, "harfbuzz.Set", set_methods, set_functions, NULL); +} diff --git a/src/luaharfbuzzsubset/luaharfbuzzsubset.c b/src/luaharfbuzzsubset/luaharfbuzzsubset.c new file mode 100644 index 0000000..03d20c0 --- /dev/null +++ b/src/luaharfbuzzsubset/luaharfbuzzsubset.c @@ -0,0 +1,43 @@ +#include "luaharfbuzzsubset.h" + +int subset(lua_State *L) { + // arguments: face and input + Face *face = (Face *)luaL_checkudata(L, 1, "harfbuzz.Face"); + SubsetInput *input = (SubsetInput*)luaL_checkudata(L, 2, "harfbuzz.SubsetInput"); + + // perform the subset + hb_face_t* subset_face = hb_subset_or_fail(*face, *input); + if (subset_face == NULL) { + lua_pushnil(L); + return 0; + } + // create a new userdata for the subset face + hb_face_t **ud = (hb_face_t **)lua_newuserdata(L, sizeof(hb_face_t *)); + *ud = subset_face; + luaL_getmetatable(L, "harfbuzz.Face"); + lua_setmetatable(L, -2); + return 1; +} + +int version (lua_State *L) { + lua_pushstring(L, hb_version_string()); + return 1; +} + +static const struct luaL_Reg lib_table [] = { + {"subset", subset}, + {"version", version}, + {NULL, NULL} +}; + +int luaopen_luaharfbuzzsubset (lua_State *L) { + lua_newtable(L); + + register_subset_input(L); + lua_setfield(L, -2, "subset_input"); + + luaL_setfuncs(L, lib_table, 0); + + return 1; +} + diff --git a/src/luaharfbuzzsubset/luaharfbuzzsubset.h b/src/luaharfbuzzsubset/luaharfbuzzsubset.h new file mode 100644 index 0000000..a02e57c --- /dev/null +++ b/src/luaharfbuzzsubset/luaharfbuzzsubset.h @@ -0,0 +1,8 @@ +#include "../common.h" + +#include + +typedef hb_subset_input_t* SubsetInput; + +// Functions to create classes and push them onto the stack +int register_subset_input(lua_State *L); diff --git a/src/luaharfbuzzsubset/subset-input.c b/src/luaharfbuzzsubset/subset-input.c new file mode 100644 index 0000000..432184c --- /dev/null +++ b/src/luaharfbuzzsubset/subset-input.c @@ -0,0 +1,80 @@ +#include "luaharfbuzzsubset.h" + +int subset_input_new(lua_State *L) { + SubsetInput *ud; + hb_subset_input_t *input; + input = hb_subset_input_create_or_fail(); + if (input == NULL) { + lua_pushnil(L); + } else { + ud = (SubsetInput *)lua_newuserdata(L, sizeof(hb_subset_input_t *)); + *ud = input; + luaL_getmetatable(L, "harfbuzz.SubsetInput"); + lua_setmetatable(L, -2); + } + return 1; +} + +// hb_subset_input_pin_axis_location +static int subset_input_pin_axis_location(lua_State *L) { + // arguments: input, face, tag, value + SubsetInput *input = (SubsetInput *)luaL_checkudata(L, 1, "harfbuzz.SubsetInput"); + Face *face = (Face *)luaL_checkudata(L, 2, "harfbuzz.Face"); + if (*face == NULL) { + lua_pushboolean(L, 0); + return 1; + } + + Tag *tag = (Tag *)luaL_checkudata(L, 3, "harfbuzz.Tag"); + lua_Number value = luaL_checknumber(L, 4); + hb_bool_t ok = hb_subset_input_pin_axis_location(*input, *face, *tag, value); + lua_pushboolean(L, ok); + return 1; +} + +// hb_subset_input_keep_everything +static int subset_input_keep_everything(lua_State *L) { + // arguments: input only + SubsetInput *input = (SubsetInput *)luaL_checkudata(L, 1, "harfbuzz.SubsetInput"); + hb_subset_input_keep_everything(*input); + return 0; +} + + +int subset_input_unicode_set(lua_State *L) { + SubsetInput *input = (SubsetInput *)luaL_checkudata(L, 1, "harfbuzz.SubsetInput"); + hb_set_t *unicode_set = hb_subset_input_unicode_set(*input); + if (unicode_set == NULL) { + lua_pushnil(L); + } else { + // add metatable for hb_set_t + hb_set_t **ud = (hb_set_t **)lua_newuserdata(L, sizeof(hb_set_t *)); + *ud = unicode_set; + luaL_getmetatable(L, "harfbuzz.Set"); + lua_setmetatable(L, -2); + } + return 1; +} + +// subset_input_destroy +static int subset_input_destroy(lua_State *L) { + SubsetInput *input = (SubsetInput *)luaL_checkudata(L, 1, "harfbuzz.SubsetInput"); + hb_subset_input_destroy(*input); + return 0; +} + +static const struct luaL_Reg subset_methods[] = { + {"__gc", subset_input_destroy}, + {"unicode_set", subset_input_unicode_set}, + {"pin_axis_location", subset_input_pin_axis_location}, + {"keep_everything", subset_input_keep_everything}, + {NULL, NULL}}; + +static const struct luaL_Reg subset_functions[] = { + {"new", subset_input_new}, + {NULL, NULL}}; + +int register_subset_input(lua_State *L) { + return register_class(L, "harfbuzz.SubsetInput", subset_methods, subset_functions, + NULL); +} diff --git a/status/done.txt b/status/done.txt index fff80d6..8b10b35 100644 --- a/status/done.txt +++ b/status/done.txt @@ -32,11 +32,16 @@ hb_language_to_string hb_script_from_iso15924_tag hb_script_from_string hb_script_to_iso15924_tag +hb_set_add hb_shape hb_shape_full hb_shape_list_shapers +hb_subset_input_create_or_fail +hb_subset_input_keep_everything +hb_subset_input_pin_axis_location +hb_subset_input_unicode_set +hb_subset_or_fail hb_tag_from_string hb_tag_to_string hb_unicode_script hb_version -