Initial commit

This commit is contained in:
Marcel Fabian Krüger 2021-12-28 10:18:21 +01:00
commit ca93f7224c
52 changed files with 7770 additions and 0 deletions

View file

@ -0,0 +1,84 @@
local hb = require("luaharfbuzz")
-- special tags
hb.Tag.NONE = hb.Tag.new()
-- special script codes (ISO 15924)
hb.Script.COMMON = hb.Script.new("Zyyy")
hb.Script.INHERITED = hb.Script.new("Zinh")
hb.Script.UNKNOWN = hb.Script.new("Zzzz")
hb.Script.INVALID = hb.Script.from_iso15924_tag(hb.Tag.NONE)
-- directions
hb.Direction.INVALID = hb.Direction.new("invalid")
hb.Direction.LTR = hb.Direction.new("ltr")
hb.Direction.RTL = hb.Direction.new("rtl")
hb.Direction.TTB = hb.Direction.new("ttb")
hb.Direction.BTT = hb.Direction.new("btt")
-- special languages
hb.Language.INVALID = hb.Language.new()
hb.shape = function(font, buf, options)
options = options or { }
-- Apply options to buffer if they are set.
if options.language then buf:set_language(options.language) end
if options.script then buf:set_script(options.script) end
if options.direction then buf:set_direction(options.direction) end
-- Guess segment properties, in case all steps above have failed
-- to set the right properties.
buf:guess_segment_properties()
local features = {}
-- Parse features
if type(options.features) == "string" then
for fs in string.gmatch(options.features, '([^,]+)') do
local feature = hb.Feature.new(fs)
if feature then
table.insert(features, hb.Feature.new(fs))
else
error(string.format("Invalid feature string: '%s'", fs))
end
end
elseif type(options.features) == "table" then
features = options.features
elseif options.features then -- non-nil but not a string or table
error("Invalid features option")
end
return hb.shape_full(font,buf,features,options.shapers or {})
end
-- For backward compatibility
hb.Buffer.HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES = hb.Buffer.CLUSTER_LEVEL_MONOTONE_GRAPHEMES
hb.Buffer.HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS = hb.Buffer.CLUSTER_LEVEL_MONOTONE_CHARACTERS
hb.Buffer.HB_BUFFER_CLUSTER_LEVEL_CHARACTERS = hb.Buffer.CLUSTER_LEVEL_CHARACTERS
hb.Buffer.HB_BUFFER_CLUSTER_LEVEL_DEFAULT = hb.Buffer.CLUSTER_LEVEL_DEFAULT
hb.Tag.HB_TAG_NONE = hb.Tag.NONE
hb.Script.HB_SCRIPT_COMMON = hb.Script.COMMON
hb.Script.HB_SCRIPT_INHERITED = hb.Script.INHERITED
hb.Script.HB_SCRIPT_UNKNOWN = hb.Script.UNKNOWN
hb.Script.HB_SCRIPT_INVALID = hb.Script.INVALID
hb.Language.HB_LANGUAGE_INVALID = hb.Language.INVALID
hb.Direction.HB_DIRECTION_INVALID = hb.Direction.INVALID
hb.Direction.HB_DIRECTION_LTR = hb.Direction.LTR
hb.Direction.HB_DIRECTION_RTL = hb.Direction.RTL
hb.Direction.HB_DIRECTION_TTB = hb.Direction.TTB
hb.Direction.HB_DIRECTION_BTT = hb.Direction.BTT
hb.Direction.HB_DIRECTION_IS_VALID = hb.Direction.is_valid
hb.Direction.HB_DIRECTION_IS_HORIZONTAL = hb.Direction.is_horizontal
hb.Direction.HB_DIRECTION_IS_VERTICAL = hb.Direction.is_vertical
hb.Direction.HB_DIRECTION_IS_FORWARD = hb.Direction.is_forward
hb.Direction.HB_DIRECTION_IS_BACKWARD = hb.Direction.is_backward
hb.Buffer.get_glyph_infos_and_positions = hb.Buffer.get_glyphs
return hb

View file

@ -0,0 +1,535 @@
-----------
-- Lua bindings to Harfbuzz.
-- * [Wiki](http://github.com/ufytex/luaharfbuzz/wiki)
-- * [Source on Github](https://github.com/ufytex/luaharfbuzz)
-- * [API Coverage Status](https://github.com/ufytex/luaharfbuzz/blob/master/status/done.txt)
--
-- @author Deepak Jois <<deepak.jois@gmail.com>>
-- @copyright 2016
-- @license MIT
-- @module harfbuzz
--- Wraps `hb_version`
-- @function version
--- Wraps `hb_shape`.
-- @param font `Font` to use for shaping
--
-- @param buffer `Buffer` to shape
--
-- @param[opt] options table containing one or more supported options:
--
-- * `direction`: A `Direction` object representing the object.
-- * `script`: A `Script` object representing the script.
-- * `language`: A `Language` object representing the language.
-- * `features`: features to enable, specified as either of the following.
-- - comma-separated list of features. See [feature string syntax reference](https://github.com/ufytex/luaharfbuzz/wiki/Feature-Strings)
-- - table of `Feature` objects
-- @function shape
--- Lua wrapper for `hb_blob_t` type
-- @type Blob
--- Wraps `hb_blob_create`.
-- Initializes a new `hb_blob_t`.
-- @param data lua string containing binary or character data.
-- @function Blob.new
--- Wraps `hb_blob_create_from_file`.
-- Initializes a new `hb_blob_t`.
-- @param filename lua string.
-- @function Blob.new_from_file
--- Wraps `hb_blob_get_length`.
-- @function Blob:get_length
--- Wraps `hb_blob_get_data`.
-- @function Blob:get_data
--- Lua wrapper for `hb_face_t` type
-- @type Face
--- Wraps `hb_face_create`.
-- Initializes a new `hb_face_t` from a `Blob` object.
-- @param blob `Blob` to read the font from.
-- @param[opt=0] font_index index of font to read.
-- @function Face.new_from_blob
--- Create a new `Face` from a file.
-- Makes a call to `Face:new_from_blob` after creating a `Blob` from the
-- file contents.
-- @param file path to font file.
-- @param[opt=0] font_index index of font to read.
-- @function Face.new
--- Wraps `hb_face_collect_unicodes`.
-- @return table of codepoints supported by the face.
-- @function Face:collect_unicodes
--- Wraps `hb_face_get_glyph_count`.
-- @function Face:get_glyph_count
--- Wraps `hb_face_reference_table`.
-- @param tag `Tag` object of the table.
-- @return `Blob` object for the face table of `tag`.
-- @function Face:get_table
--- Wraps `hb_face_get_table_tags`.
-- @return table of `Tag`s representing face table tags.
-- @function Face:get_table_tags
--- Wraps `hb_face_get_upem`.
-- @function Face:get_upem
--- Wraps `hb_ot_color_has_palettes`.
-- @function Face:ot_color_has_palettes
--- Wraps `hb_ot_color_palette_get_count`.
-- @function Face:ot_color_palette_get_count
--- Wraps `hb_ot_color_palette_get_colors`.
-- @function Face:ot_color_palette_get_colors
--- Wraps `hb_ot_color_has_layers`.
-- @function Face:ot_color_has_layers
--- Wraps `hb_ot_color_glyph_get_layers`.
-- @function Face:ot_color_glyph_get_layers
--- Wraps `hb_ot_color_has_png`.
-- @function Face:ot_color_has_png
--- Wraps `hb_ot_layout_table_get_script_tags`.
-- @function Face:ot_layout_get_script_tags
--- Wraps `hb_ot_layout_script_get_language_tags`.
-- @function Face:ot_layout_get_language_tags
--- Wraps `hb_ot_layout_language_get_feature_tags`.
-- @function Face:ot_layout_get_feature_tags
--- Wraps `hb_ot_layout_table_find_script`.
-- @function Face:ot_layout_find_script
--- Wraps `hb_ot_layout_script_find_language`.
-- @function Face:ot_layout_find_language
--- Wraps `hb_ot_layout_language_find_feature`.
-- @function Face:ot_layout_find_feature
--- Lua wrapper for `hb_font_t` type
-- @type Font
--- Wraps `hb_font_create`, and sets up some defaults for scale and shaping functions.
-- Initializes a new `hb_font_t` from a `Face` object. Sets the default scale
-- to the faces upem value, and sets the font shaping functions by
-- calling `hb_ot_font_set_funcs` on it.
-- @param face `Face` object.
-- @function Font.new
--- Wraps `hb_font_get_scale`.
-- @return two values for the x-scale and y-scale of the font.
-- @function Font:get_scale
--- Wraps `hb_font_set_scale`.
-- @param x_scale desired x-scale of font.
-- @param y_scale desired y-scale of font.
-- @function Font:set_scale
--- Wraps `hb_font_get_h_extents`.
-- @return font extents table for horizontal direction, contains the following
-- or `nil` if HarfBuzz fails to load font extents:
--
-- * `ascender`: typographic ascender.
-- * `descender`: typographic descender.
-- * `line_gap`: line spacing gap.
-- @function Font:get_h_extents
--- Wraps `hb_font_get_v_extents`.
-- @return font extents table for vertical direction, similar to
-- `Font:get_h_extents`, or `nil` if HarfBuzz fails to load font extents:
-- @function Font:get_v_extents
--- Wraps `hb_font_get_glyph_extents`.
-- @param glyph index inside the font.
-- @return extents table contains the following or `nil` if HarfBuzz fails to
-- load glyph extents:
--
-- * `x_bearing`: left side of glyph from origin.
-- * `y_bearing`: top side of glyph from origin.
-- * `width`: distance from left to right side.
-- * `height`: distance from top to bottom side.
-- @function Font:get_glyph_extents
--- Wraps `hb_font_get_glyph_name`.
-- @param glyph index inside the font.
-- @return name of the glyph or nil.
-- @function Font:get_glyph_name
--- Wraps `hb_font_get_glyph_from_name`.
-- @param name of the glyph.
-- @return glyph index inside the font or nil.
-- @function Font:get_glyph_from_name
--- Wraps `hb_font_get_glyph_h_advance`.
-- @param glyph index inside the font.
-- @return advance glyph advance of the glyph in horizontal direction.
-- @function Font:get_glyph_h_advance
--- Wraps `hb_font_get_glyph_v_advance`.
-- @param glyph index inside the font.
-- @return advance glyph advance of the glyph in vertical direction.
-- @function Font:get_glyph_v_advance
--- Wraps `hb_font_get_nominal_glyph`.
-- @param codepoint.
-- @return glyph index or `nil` if `codepoint` is not supported by the font.
-- @function Font:get_nominal_glyph
--- Wraps `hb_ot_color_glyph_get_png`.
-- @function Font:ot_color_glyph_get_png
--- Lua wrapper for `hb_buffer_t` type.
-- @type Buffer
--- Wraps `hb_buffer_create`.
-- @function Buffer.new
--- Wraps `hb_buffer_add_utf8`.
-- @param text UTF8 encoded string.
-- @param[opt=0] item_offset 0-indexed offset in `text`, from where to start adding.
-- @param[opt=-1] item_length length to add from `item_offset`. `-1` adds till end of `text`.
-- @function Buffer:add_utf8
--- Wraps `hb_buffer_add_codepoints`.
-- @param text table with codepoints as lua numbers.
-- @param[opt=0] item_offset 0-indexed offset in `text`, from where to start adding.
-- @param[opt=-1] item_length length to add from `item_offset`. `-1` adds till end of&nbsp;`text`.
-- @function Buffer:add_codepoints
--- Wraps `hb_buffer_set_direction`.
-- @param dir A `Direction` object.
-- @function Buffer:set_direction
--- Wraps `hb_buffer_get_direction`.
-- @return A `Direction` object.
-- @function Buffer:get_direction
--- Wraps `hb_buffer_set_script`.
-- @param script A `Script` object.
-- @function Buffer:set_script
--- Wraps `hb_buffer_get_script`.
-- @return A `Script` object.
-- @function Buffer:get_script
--- Wraps `hb_buffer_set_language`.
-- @param lang A `Language` object
-- @function Buffer:set_language
--- Wraps `hb_buffer_get_language`.
-- @return A `Language` object
-- @function Buffer:get_language
--- Wraps `hb_buffer_reverse`.
-- @function Buffer:reverse
--- Wraps `hb_buffer_get_length`.
-- @function Buffer:get_length
--- Wraps `hb_buffer_get_cluster_level`.
-- @return see [Cluster Levels](#Cluster_Levels)
-- @function Buffer:get_cluster_level
--- Wraps `hb_buffer_set_cluster_level`.
-- @param level see [Cluster Levels](#Cluster_Levels)
-- @function Buffer:set_cluster_level
--- Wraps `hb_buffer_guess_segment_properties`.
-- @function Buffer:guess_segment_properties
--- Helper method to get shaped glyph data.
-- Calls `hb_buffer_get_glyph_infos`, `hb_buffer_get_glyph_positions` and
-- `hb_glyph_info_get_glyph_flags`, and assembles the data into a Lua table.
-- @return table containing data for each glyph, in a nested table. Each nested
-- table contains the following:
--
-- * `x_advance`: horizontal advance.
-- * `y_advance`: vertical advance.
-- * `x_offset`: horizontal displacement.
-- * `y_offset`: vertical displacement.
-- * `cluster`: glyph cluster index within input.
-- * `codepoint`: glyph index inside the font _(this field name is a bit misleading, but thats what Harfbuzz uses)_.
-- * `flags`: glyph flags
-- @function Buffer:get_glyphs
--- Cluster Levels.
-- See [Harfbuzz docs](http://behdad.github.io/harfbuzz/clusters.html) for more details
-- about what each of these levels mean.
-- @section
--- Wraps `HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES`.
-- @field Buffer.CLUSTER_LEVEL_MONOTONE_GRAPHEMES
--- Wraps `HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS`.
-- @field Buffer.CLUSTER_LEVEL_MONOTONE_CHARACTERS
--- Wraps `HB_BUFFER_CLUSTER_LEVEL_CHARACTERS`.
-- @field Buffer.CLUSTER_LEVEL_CHARACTERS
--- Wraps `HB_BUFFER_CLUSTER_LEVEL_DEFAULT`.
-- @field Buffer.CLUSTER_LEVEL_DEFAULT
--- Wraps `HB_GLYPH_FLAG_UNSAFE_TO_BREAK`.
-- @field Buffer.GLYPH_FLAG_UNSAFE_TO_BREAK
--- Wraps `HB_GLYPH_FLAG_DEFINED`.
-- @field Buffer.GLYPH_FLAG_DEFINED
--- Lua wrapper for `hb_feature_t` type
-- @type Feature
--- Wraps `hb_feature_from_string`
-- @param feature_string See [feature string syntax reference](https://github.com/ufytex/luaharfbuzz/wiki/Feature-Strings)
-- @function Feature.new
--- Wraps `hb_feature_to_string`.
-- Enables nice output with `tostring(…)`.
-- @function Feature:__tostring
--- Lua wrapper for `hb_tag_t` type.
-- @type Tag
--- Wraps `hb_tag_from_string`.
-- @param string to be converted to a `Tag` object.
-- @return a `Tag` object.
-- @function Tag.new
--- Wraps `hb_tag_to_string`. Enable nice output with `tostring(…)`.
-- @return Returns a string representation for the tag object.
-- @function Tag:__to_string
--- Enables equality comparisions with `==` between two tags.
-- @return `true` or `false` depending on whether the two tags are equal.
-- @function Tag:__eq
--- Lua wrapper for `hb_script_t` type.
-- @type Script
--- Wraps `hb_script_from_string`.
-- @param script 4-letter script code according to the [ISO 15924 standard](http://www.unicode.org/iso15924/iso15924-num.html).
-- @return a `Script` object.
-- @function Script.new
--- Wraps `hb_script_from_iso15924_tag`
-- @param tag a `Tag` object representing a [ISO 15924 script](http://www.unicode.org/iso15924/iso15924-num.html).
-- @function Script.from_iso15924_tag
--- Wraps `hb_script_to_iso15924_tag`.
-- @return a `Tag` object representing the script.
-- @function Script:to_iso15924_tag
--- Enable nice output with `tostring(…)`
-- @return Returns a 4-letter [ISO 15924 script code](http://www.unicode.org/iso15924/iso15924-num.html) for the script object.
-- @function Script:__to_string
--- Enables equality comparisions with `==` between two scripts.
-- @return `true` or `false` depending on whether the two scripts are equal.
-- @function Script:__eq
--- Predefined Script Codes.
-- Predefined directions that correspond to their original definitions in Harfbuzz.
-- @section
--- Wraps `HB_SCRIPT_COMMON`.
-- @field Script.COMMON
--- Wraps `HB_SCRIPT_INHERITED`.
-- @field Script.INHERITED
--- Wraps `HB_SCRIPT_UNKNOWN`.
-- @field Script.UNKNOWN
--- Wraps `HB_SCRIPT_INVALID`.
-- @field Script.INVALID
--- Lua wrapper for `hb_direction_t` type.
-- @type Direction
--- Wraps `hb_direction_from_string`.
-- @param dir can be one of `ltr`, `rtl`, `ttb`, `btt` or `invalid`.
-- @return a `Direction` object.
-- @function Direction.new
--- Wraps `hb_direction_to_string`. Enable nice output with `tostring(…)`.
-- @return Returns a string representation for direction.
-- @function Direction:__to_string
--- Enables equality comparisions with `==` between two directions.
-- @return `true` or `false` depending on whether the two tags are equal.
-- @function Direction:__eq
--- Wraps `HB_DIRECTION_IS_VALID`.
-- @return a boolean value
-- @function Direction:is_valid
--- Wraps `HB_DIRECTION_IS_HORIZONTAL`.
-- @return a boolean value
-- @function Direction:is_horizontal
--- Wraps `HB_DIRECTION_IS_VERTICAL`.
-- @return a boolean value
-- @function Direction:is_vertical
--- Wraps `HB_DIRECTION_IS_FORWARD`.
-- @return a boolean value
-- @function Direction:is_forward
--- Wraps `HB_DIRECTION_IS_BACKWARD`.
-- @return a boolean value
-- @function Direction:is_backward
--- Predefined directions.
-- Predefined directions that correspond to their original definitions in Harfbuzz.
-- @section
--- Wraps `HB_DIRECTION_LTR`.
-- @field Direction.LTR
--- Wraps `HB_DIRECTION_RTL`.
-- @field Direction.RTL
--- Wraps `HB_DIRECTION_TTB`.
-- @field Direction.TTB
--- Wraps `HB_DIRECTION_LTR`.
-- @field Direction.BTT
--- Lua wrapper for `hb_language_t` type.
-- @type Language
--- Wraps `hb_language_from_string`.
-- @param lang [three-letter language tag](http://www.microsoft.com/typography/otspec/languagetags.htm) to be converted to a `Language` object.
-- @return a `Language` object.
-- @function Language.new
--- Wraps `hb_language_to_string`. Enable nice output with `tostring(…)`.
-- @return Returns a string representation for the language object.
-- @function Language:__to_string
--- Enables equality comparisions with `==` between two languages.
-- @return `true` or `false` depending on whether the two languages are equal.
-- @function Language:__eq
--- Predefined languages.
-- Predefined languages that correspond to their original definitions in Harfbuzz.
-- @section
--- Wraps `HB_LANGUAGE_INVALID`.
-- @field Language.INVALID
--- Unicode functions.
-- @section
--- Wraps `hb_unicode_script`
-- @param char Unicode codepoint
-- @return a `Script` object.
-- @function unicode.script
--- Predefined Name IDs.
-- Predefined OpenType 'name' table name identifier.
-- @section
--- Wraps `HB_OT_NAME_ID_COPYRIGHT`
-- @field ot.NAME_ID_COPYRIGHT
--- Wraps `HB_OT_NAME_ID_FONT_FAMILY`
-- @field ot.NAME_ID_FONT_FAMILY
--- Wraps `HB_OT_NAME_ID_FONT_SUBFAMILY`
-- @field ot.NAME_ID_FONT_SUBFAMILY
--- Wraps `HB_OT_NAME_ID_UNIQUE_ID`
-- @field ot.NAME_ID_UNIQUE_ID
--- Wraps `HB_OT_NAME_ID_FULL_NAME`
-- @field ot.NAME_ID_FULL_NAME
--- Wraps `HB_OT_NAME_ID_VERSION_STRING`
-- @field ot.NAME_ID_VERSION_STRING
--- Wraps `HB_OT_NAME_ID_POSTSCRIPT_NAME`
-- @field ot.NAME_ID_POSTSCRIPT_NAME
--- Wraps `HB_OT_NAME_ID_TRADEMARK`
-- @field ot.NAME_ID_TRADEMARK
--- Wraps `HB_OT_NAME_ID_MANUFACTURER`
-- @field ot.NAME_ID_MANUFACTURER
--- Wraps `HB_OT_NAME_ID_DESIGNER`
-- @field ot.NAME_ID_DESIGNER
--- Wraps `HB_OT_NAME_ID_DESCRIPTION`
-- @field ot.NAME_ID_DESCRIPTION
--- Wraps `HB_OT_NAME_ID_VENDOR_URL`
-- @field ot.NAME_ID_VENDOR_URL
--- Wraps `HB_OT_NAME_ID_DESIGNER_URL`
-- @field ot.NAME_ID_DESIGNER_URL
--- Wraps `HB_OT_NAME_ID_LICENSE`
-- @field ot.NAME_ID_LICENSE
--- Wraps `HB_OT_NAME_ID_LICENSE_URL`
-- @field ot.NAME_ID_LICENSE_URL
--- Wraps `HB_OT_NAME_ID_TYPOGRAPHIC_FAMILY`
-- @field ot.NAME_ID_TYPOGRAPHIC_FAMILY
--- Wraps `HB_OT_NAME_ID_TYPOGRAPHIC_SUBFAMILY`
-- @field ot.NAME_ID_TYPOGRAPHIC_SUBFAMILY
--- Wraps `HB_OT_NAME_ID_MAC_FULL_NAME`
-- @field ot.NAME_ID_MAC_FULL_NAME
--- Wraps `HB_OT_NAME_ID_SAMPLE_TEXT`
-- @field ot.NAME_ID_SAMPLE_TEXT
--- Wraps `HB_OT_NAME_ID_CID_FINDFONT_NAME`
-- @field ot.NAME_ID_CID_FINDFONT_NAME
--- Wraps `HB_OT_NAME_ID_WWS_FAMILY`
-- @field ot.NAME_ID_WWS_FAMILY
--- Wraps `HB_OT_NAME_ID_WWS_SUBFAMILY`
-- @field ot.NAME_ID_WWS_SUBFAMILY
--- Wraps `HB_OT_NAME_ID_LIGHT_BACKGROUND`
-- @field ot.NAME_ID_LIGHT_BACKGROUND
--- Wraps `HB_OT_NAME_ID_DARK_BACKGROUND`
-- @field ot.NAME_ID_DARK_BACKGROUND
--- Wraps `HB_OT_NAME_ID_VARIATIONS_PS_PREFIX`
-- @field ot.NAME_ID_VARIATIONS_PS_PREFIX
--- Wraps `HB_OT_NAME_ID_INVALID`
-- @field ot.NAME_ID_INVALID
--- Wraps `HB_OT_LAYOUT_NO_SCRIPT_INDEX`
-- @field ot.LAYOUT_NO_SCRIPT_INDEX
--- Wraps `HB_OT_LAYOUT_NO_FEATURE_INDEX`
-- @field ot.LAYOUT_NO_FEATURE_INDEX
--- Wraps `HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX`
-- @field ot.LAYOUT_DEFAULT_LANGUAGE_INDEX
--- Wraps `HB_OT_LAYOUT_NO_VARIATIONS_INDEX`
-- @field ot.LAYOUT_NO_VARIATIONS_INDEX

View file

@ -0,0 +1,60 @@
#include "luaharfbuzz.h"
static int blob_new(lua_State *L) {
Blob *b;
size_t data_l;
const char *data = luaL_checklstring(L, 1, &data_l);
b = (Blob *)lua_newuserdata(L, sizeof(*b));
luaL_getmetatable(L, "harfbuzz.Blob");
lua_setmetatable(L, -2);
*b = hb_blob_create(data, data_l, HB_MEMORY_MODE_DUPLICATE, (void*)data, NULL);
return 1;
}
static int blob_new_from_file(lua_State *L) {
Blob *b;
const char *file_name = luaL_checkstring(L, 1);
b = (Blob *)lua_newuserdata(L, sizeof(*b));
luaL_getmetatable(L, "harfbuzz.Blob");
lua_setmetatable(L, -2);
*b = hb_blob_create_from_file(file_name);
return 1;
}
static int blob_get_length(lua_State *L) {
Blob *b = (Blob *)luaL_checkudata(L, 1, "harfbuzz.Blob");
lua_pushinteger(L, hb_blob_get_length(*b));
return 1;
}
static int blob_get_data(lua_State *L) {
Blob *b = (Blob *)luaL_checkudata(L, 1, "harfbuzz.Blob");
unsigned int l;
const char *d;
d = hb_blob_get_data(*b, &l);
lua_pushlstring(L, d, l);
return 1;
}
static const struct luaL_Reg blob_methods[] = {
{ "get_length", blob_get_length },
{ "get_data", blob_get_data },
{ NULL, NULL }
};
static const struct luaL_Reg blob_functions[] = {
{ "new", blob_new },
{ "new_from_file", blob_new_from_file },
{ NULL, NULL }
};
int register_blob(lua_State *L) {
return register_class(L, "harfbuzz.Blob", blob_methods, blob_functions, NULL);
}

View file

@ -0,0 +1,338 @@
#include "luaharfbuzz.h"
static int buffer_new(lua_State *L) {
Buffer *b;
b = (Buffer *)lua_newuserdata(L, sizeof(*b));
luaL_getmetatable(L, "harfbuzz.Buffer");
lua_setmetatable(L, -2);
*b = hb_buffer_create();
return 1;
}
static int buffer_guess_segment_properties(lua_State *L) {
Buffer *b = (Buffer *)luaL_checkudata(L, 1, "harfbuzz.Buffer");
hb_buffer_guess_segment_properties(*b);
return 0;
}
static int buffer_get_direction(lua_State *L) {
Buffer *b = (Buffer *)luaL_checkudata(L, 1, "harfbuzz.Buffer");
Direction *dp = (Direction *)lua_newuserdata(L, sizeof(*dp));
luaL_getmetatable(L, "harfbuzz.Direction");
lua_setmetatable(L, -2);
*dp = hb_buffer_get_direction(*b);
return 1;
}
static int buffer_set_direction(lua_State *L) {
Buffer *b = (Buffer *)luaL_checkudata(L, 1, "harfbuzz.Buffer");
Direction* dir = (Direction *)luaL_checkudata(L, 2, "harfbuzz.Direction");
hb_buffer_set_direction(*b, *dir);
return 0;
}
static int buffer_get_flags(lua_State *L) {
Buffer *b = (Buffer *)luaL_checkudata(L, 1, "harfbuzz.Buffer");
lua_pushinteger(L, hb_buffer_get_flags(*b));
return 1;
}
static int buffer_set_flags(lua_State *L) {
Buffer *b = (Buffer *)luaL_checkudata(L, 1, "harfbuzz.Buffer");
unsigned int l = luaL_checkinteger(L, 2);
hb_buffer_set_flags(*b, l);
return 0;
}
static int buffer_get_language(lua_State *L) {
Buffer *b = (Buffer *)luaL_checkudata(L, 1, "harfbuzz.Buffer");
Language *lp = (Language *)lua_newuserdata(L, sizeof(*lp));
luaL_getmetatable(L, "harfbuzz.Language");
lua_setmetatable(L, -2);
*lp = hb_buffer_get_language(*b);
return 1;
}
static int buffer_set_language(lua_State *L) {
Buffer *b = (Buffer *)luaL_checkudata(L, 1, "harfbuzz.Buffer");
Language *lang = (Language *)luaL_checkudata(L, 2, "harfbuzz.Language");
hb_buffer_set_language(*b, *lang);
return 0;
}
static int buffer_get_script(lua_State *L) {
Buffer *b = (Buffer *)luaL_checkudata(L, 1, "harfbuzz.Buffer");
Script *sp = (Script *)lua_newuserdata(L, sizeof(*sp));
luaL_getmetatable(L, "harfbuzz.Script");
lua_setmetatable(L, -2);
*sp = hb_buffer_get_script(*b);
return 1;
}
static int buffer_set_script(lua_State *L) {
Buffer *b = (Buffer *)luaL_checkudata(L, 1, "harfbuzz.Buffer");
Script *script = (Script *)luaL_checkudata(L, 2, "harfbuzz.Script");
hb_buffer_set_script(*b, *script);
return 0;
}
static int buffer_get_invisible_glyph(lua_State *L) {
Buffer *b = (Buffer *)luaL_checkudata(L, 1, "harfbuzz.Buffer");
lua_pushinteger(L, hb_buffer_get_invisible_glyph(*b));
return 1;
}
static int buffer_set_invisible_glyph(lua_State *L) {
Buffer *b = (Buffer *)luaL_checkudata(L, 1, "harfbuzz.Buffer");
hb_codepoint_t cp = (hb_codepoint_t) luaL_checkinteger(L, 2);
hb_buffer_set_invisible_glyph(*b, cp);
return 0;
}
static int buffer_get_replacement_codepoint(lua_State *L) {
Buffer *b = (Buffer *)luaL_checkudata(L, 1, "harfbuzz.Buffer");
lua_pushinteger(L, hb_buffer_get_replacement_codepoint(*b));
return 1;
}
static int buffer_set_replacement_codepoint(lua_State *L) {
Buffer *b = (Buffer *)luaL_checkudata(L, 1, "harfbuzz.Buffer");
hb_codepoint_t cp = (hb_codepoint_t) luaL_checkinteger(L, 2);
hb_buffer_set_replacement_codepoint(*b, cp);
return 0;
}
static int buffer_add(lua_State *L) {
Buffer *b = (Buffer *)luaL_checkudata(L, 1, "harfbuzz.Buffer");
hb_codepoint_t c = (hb_codepoint_t) luaL_checkinteger(L, 2);
unsigned int cluster = luaL_checkinteger(L, 3);
hb_buffer_add(*b, c, cluster);
return 0;
}
static int buffer_add_codepoints(lua_State *L) {
Buffer *b = (Buffer *)luaL_checkudata(L, 1, "harfbuzz.Buffer");
unsigned int item_offset;
int item_length;
luaL_checktype(L, 2, LUA_TTABLE);
item_offset = luaL_optinteger(L, 3, 0);
item_length = luaL_optinteger(L, 4, -1);
int n = lua_rawlen(L, 2);
hb_codepoint_t *text = (hb_codepoint_t *) malloc(n * sizeof(hb_codepoint_t));
for (unsigned int i = 0; i != n; ++i) {
lua_geti(L, 2, i + 1);
hb_codepoint_t c = (hb_codepoint_t) luaL_checkinteger(L, -1);
text[i] = c;
lua_pop(L, 1);
}
hb_buffer_add_codepoints(*b, text, n, item_offset, item_length);
free(text);
return 0;
}
static int buffer_clear_contents(lua_State *L) {
Buffer *b = (Buffer *)luaL_checkudata(L, 1, "harfbuzz.Buffer");
hb_buffer_clear_contents(*b);
return 0;
}
static int buffer_reset(lua_State *L) {
Buffer *b = (Buffer *)luaL_checkudata(L, 1, "harfbuzz.Buffer");
hb_buffer_reset(*b);
return 0;
}
static int buffer_add_utf8(lua_State *L) {
Buffer *b = (Buffer *)luaL_checkudata(L, 1, "harfbuzz.Buffer");
const char *text;
unsigned int item_offset;
int item_length;
text = luaL_checkstring(L, 2);
item_offset = luaL_optinteger(L, 3, 0);
item_length = luaL_optinteger(L, 4, -1);
hb_buffer_add_utf8(*b, text, -1, item_offset, item_length);
return 0;
}
static int buffer_destroy(lua_State *L) {
Buffer *b = (Buffer *)luaL_checkudata(L, 1, "harfbuzz.Buffer");
hb_buffer_destroy(*b);
return 0;
}
static int buffer_get_glyphs(lua_State *L) {
Buffer *buf = (Buffer *)luaL_checkudata(L, 1, "harfbuzz.Buffer");
// Get glyph info and positions out of buffer
unsigned int len = hb_buffer_get_length(*buf);
hb_glyph_info_t *info = hb_buffer_get_glyph_infos(*buf, NULL);
hb_glyph_position_t *pos = hb_buffer_get_glyph_positions(*buf, NULL);
hb_glyph_flags_t flags;
unsigned int i;
// Create Lua table and push glyph data onto it.
lua_createtable(L, len, 0); // parent table
for (i = 0; i < len; i++) {
lua_pushinteger(L, i+1); // 1-indexed key parent table
lua_createtable(L, 0, 7); // child table
lua_pushinteger(L, info[i].codepoint);
lua_setfield(L, -2, "codepoint");
lua_pushinteger(L, info[i].cluster);
lua_setfield(L, -2, "cluster");
lua_pushnumber(L, pos[i].x_advance);
lua_setfield(L, -2, "x_advance");
lua_pushnumber(L, pos[i].y_advance);
lua_setfield(L, -2, "y_advance");
lua_pushnumber(L, pos[i].x_offset);
lua_setfield(L, -2, "x_offset");
lua_pushnumber(L, pos[i].y_offset);
lua_setfield(L, -2, "y_offset");
flags = hb_glyph_info_get_glyph_flags(&(info[i]));
if (flags & HB_GLYPH_FLAG_DEFINED) {
lua_pushnumber(L, flags);
lua_setfield(L, -2, "flags");
}
lua_settable(L, -3); // Add child table at index i+1 to parent table
}
return 1;
}
static int buffer_reverse(lua_State *L) {
Buffer *b = (Buffer *)luaL_checkudata(L, 1, "harfbuzz.Buffer");
hb_buffer_reverse(*b);
return 0;
}
static int buffer_get_length(lua_State *L) {
Buffer *b = (Buffer *)luaL_checkudata(L, 1, "harfbuzz.Buffer");
lua_pushinteger(L, hb_buffer_get_length(*b));
return 1;
}
static int buffer_get_cluster_level(lua_State *L) {
Buffer *b = (Buffer *)luaL_checkudata(L, 1, "harfbuzz.Buffer");
lua_pushinteger(L, hb_buffer_get_cluster_level(*b));
return 1;
}
static int buffer_set_cluster_level(lua_State *L) {
Buffer *b = (Buffer *)luaL_checkudata(L, 1, "harfbuzz.Buffer");
unsigned int l = luaL_checkinteger(L, 2);
hb_buffer_set_cluster_level(*b, l);
return 0;
}
static int buffer_pre_allocate(lua_State *L) {
Buffer *b = (Buffer *)luaL_checkudata(L, 1, "harfbuzz.Buffer");
unsigned int n = luaL_checkinteger(L, 2);
lua_pushboolean(L, hb_buffer_pre_allocate(*b, n));
return 1;
}
static const struct luaL_Reg buffer_methods[] = {
{ "__gc", buffer_destroy },
{ "add", buffer_add },
{ "add_utf8", buffer_add_utf8 },
{ "add_codepoints", buffer_add_codepoints },
{ "clear_contents", buffer_clear_contents },
{ "set_direction", buffer_set_direction },
{ "get_direction", buffer_get_direction },
{ "set_flags", buffer_set_flags },
{ "get_flags", buffer_get_flags },
{ "set_language", buffer_set_language },
{ "get_language", buffer_get_language },
{ "set_script", buffer_set_script },
{ "get_script", buffer_get_script },
{ "set_invisible_glyph", buffer_set_invisible_glyph },
{ "get_invisible_glyph", buffer_get_invisible_glyph },
{ "set_replacement_codepoint", buffer_set_replacement_codepoint },
{ "get_replacement_codepoint", buffer_get_replacement_codepoint },
{ "get_glyphs", buffer_get_glyphs },
{ "guess_segment_properties", buffer_guess_segment_properties },
{ "reset", buffer_reset },
{ "reverse", buffer_reverse },
{ "get_length", buffer_get_length },
{ "get_cluster_level", buffer_get_cluster_level },
{ "set_cluster_level", buffer_set_cluster_level },
{ "pre_allocate", buffer_pre_allocate },
{ NULL, NULL }
};
static const struct luaL_Reg buffer_functions[] = {
{ "new", buffer_new },
{ NULL, NULL }
};
static const struct luahb_constant_t buffer_constants[] = {
{ "CLUSTER_LEVEL_MONOTONE_GRAPHEMES", HB_BUFFER_CLUSTER_LEVEL_MONOTONE_GRAPHEMES },
{ "CLUSTER_LEVEL_MONOTONE_CHARACTERS", HB_BUFFER_CLUSTER_LEVEL_MONOTONE_CHARACTERS },
{ "CLUSTER_LEVEL_CHARACTERS", HB_BUFFER_CLUSTER_LEVEL_CHARACTERS },
{ "CLUSTER_LEVEL_DEFAULT", HB_BUFFER_CLUSTER_LEVEL_DEFAULT },
{ "FLAG_DEFAULT", HB_BUFFER_FLAG_DEFAULT },
{ "FLAG_BOT", HB_BUFFER_FLAG_BOT },
{ "FLAG_EOT", HB_BUFFER_FLAG_EOT },
{ "FLAG_PRESERVE_DEFAULT_IGNORABLES", HB_BUFFER_FLAG_PRESERVE_DEFAULT_IGNORABLES },
{ "FLAG_REMOVE_DEFAULT_IGNORABLES", HB_BUFFER_FLAG_REMOVE_DEFAULT_IGNORABLES },
{ "FLAG_DO_NOT_INSERT_DOTTED_CIRCLE", HB_BUFFER_FLAG_DO_NOT_INSERT_DOTTED_CIRCLE },
{ "GLYPH_FLAG_UNSAFE_TO_BREAK", HB_GLYPH_FLAG_UNSAFE_TO_BREAK },
{ "GLYPH_FLAG_DEFINED", HB_GLYPH_FLAG_DEFINED },
{ NULL, 0 }
};
int register_buffer(lua_State *L) {
return register_class(L, "harfbuzz.Buffer", buffer_methods, buffer_functions, buffer_constants);
}

View file

@ -0,0 +1,25 @@
// Utility functions to create Lua classes.
#include "luaharfbuzz.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);
lua_pushvalue(L, -1);
lua_setfield(L, -2, "__index");
if (constants) {
while (constants->name) {
lua_pushinteger(L, constants->value);
lua_setfield(L, -2, constants->name);
constants++;
}
}
luaL_setfuncs(L, methods, 0);
lua_pop(L, 1);
lua_newtable(L);
luaL_setfuncs(L, functions, 0);
luaL_getmetatable(L, name);
lua_setmetatable(L, -2);
return 1;
}

View file

@ -0,0 +1,84 @@
// harfbuzz.Feature
#include "luaharfbuzz.h"
static int direction_new(lua_State *L) {
Direction *d;
const char *dir = luaL_checkstring(L, 1);
d = (Direction *)lua_newuserdata(L, sizeof(*d));
luaL_getmetatable(L, "harfbuzz.Direction");
lua_setmetatable(L, -2);
*d = hb_direction_from_string(dir, -1);
return 1;
}
static int direction_to_string(lua_State *L) {
Direction* d = (Direction *)luaL_checkudata(L, 1, "harfbuzz.Direction");
lua_pushstring(L, hb_direction_to_string(*d));
return 1;
}
static int direction_equals(lua_State *L) {
Direction* lhs = (Direction *)luaL_checkudata(L, 1, "harfbuzz.Direction");
Direction* rhs = (Direction *)luaL_checkudata(L, 2, "harfbuzz.Direction");
lua_pushboolean(L, *lhs == *rhs);
return 1;
}
static int direction_is_valid(lua_State *L) {
Direction* d = (Direction *)luaL_checkudata(L, 1, "harfbuzz.Direction");
lua_pushboolean(L, HB_DIRECTION_IS_VALID(*d));
return 1;
}
static int direction_is_horizontal(lua_State *L) {
Direction* d = (Direction *)luaL_checkudata(L, 1, "harfbuzz.Direction");
lua_pushboolean(L, HB_DIRECTION_IS_HORIZONTAL(*d));
return 1;
}
static int direction_is_vertical(lua_State *L) {
Direction* d = (Direction *)luaL_checkudata(L, 1, "harfbuzz.Direction");
lua_pushboolean(L, HB_DIRECTION_IS_VERTICAL(*d));
return 1;
}
static int direction_is_forward(lua_State *L) {
Direction* d = (Direction *)luaL_checkudata(L, 1, "harfbuzz.Direction");
lua_pushboolean(L, HB_DIRECTION_IS_FORWARD(*d));
return 1;
}
static int direction_is_backward(lua_State *L) {
Direction* d = (Direction *)luaL_checkudata(L, 1, "harfbuzz.Direction");
lua_pushboolean(L, HB_DIRECTION_IS_BACKWARD(*d));
return 1;
}
static const struct luaL_Reg direction_methods[] = {
{ "__tostring", direction_to_string },
{ "__eq", direction_equals },
{ "is_valid", direction_is_valid },
{ "is_horizontal", direction_is_horizontal },
{ "is_vertical", direction_is_vertical },
{ "is_forward", direction_is_forward },
{ "is_backward", direction_is_backward },
{ NULL, NULL }
};
static const struct luaL_Reg direction_functions[] = {
{ "new", direction_new },
{ NULL, NULL }
};
int register_direction(lua_State *L) {
return register_class(L, "harfbuzz.Direction", direction_methods, direction_functions, NULL);
}

View file

@ -0,0 +1,466 @@
#include "luaharfbuzz.h"
/* Size of static arrays we use to avoid heap allocating memory when reading
* data from HarfBuzz. */
#define STATIC_ARRAY_SIZE 128
static int face_new(lua_State *L) {
Face *f;
hb_blob_t *blob;
hb_face_t *face;
const char *file_name = luaL_checkstring(L, 1);
unsigned int face_index = (unsigned int) luaL_optinteger(L, 2, 0);
blob = hb_blob_create_from_file(file_name);
face = hb_face_create(blob, face_index);
if (blob == hb_blob_get_empty() || face == hb_face_get_empty()) {
lua_pushnil(L);
} else {
f = (Face *)lua_newuserdata(L, sizeof(*f));
*f = face;
luaL_getmetatable(L, "harfbuzz.Face");
lua_setmetatable(L, -2);
}
return 1;
}
static int face_new_from_blob(lua_State *L) {
Face *f;
hb_face_t *face;
Blob *blob = luaL_checkudata(L, 1, "harfbuzz.Blob");
unsigned int face_index = (unsigned int) luaL_optinteger(L, 2, 0);
face = hb_face_create(*blob, face_index);
if (*blob == hb_blob_get_empty() || face == hb_face_get_empty()) {
lua_pushnil(L);
} else {
f = (Face *)lua_newuserdata(L, sizeof(*f));
*f = face;
luaL_getmetatable(L, "harfbuzz.Face");
lua_setmetatable(L, -2);
}
return 1;
}
static int face_get_glyph_count(lua_State *L) {
Face *f = (Face *)luaL_checkudata(L, 1, "harfbuzz.Face");
lua_pushinteger(L, hb_face_get_glyph_count(*f));
return 1;
}
static int face_get_name(lua_State *L) {
Face *f = (Face *)luaL_checkudata(L, 1, "harfbuzz.Face");
hb_ot_name_id_t name_id = (hb_ot_name_id_t) luaL_checkinteger(L, 2);
hb_language_t lang = HB_LANGUAGE_INVALID;
char name[STATIC_ARRAY_SIZE];
unsigned int text_size = STATIC_ARRAY_SIZE, len;
if (lua_gettop(L) > 2)
lang = *((Language*)luaL_checkudata(L, 3, "harfbuzz.Language"));
len = hb_ot_name_get_utf8(*f, name_id, lang, &text_size, name);
if (len) {
if (len < STATIC_ARRAY_SIZE) {
lua_pushstring(L, name);
} else {
char *name = malloc(len + 1);
text_size = len + 1;
hb_ot_name_get_utf8(*f, name_id, lang, &text_size, name);
lua_pushstring(L, name);
free(name);
}
} else {
lua_pushnil(L);
}
return 1;
}
static int face_get_table(lua_State *L) {
Face *f = (Face *)luaL_checkudata(L, 1, "harfbuzz.Face");
Tag *t = (Tag *)luaL_checkudata(L, 2, "harfbuzz.Tag");
Blob *b;
b = (Blob *)lua_newuserdata(L, sizeof(*b));
luaL_getmetatable(L, "harfbuzz.Blob");
lua_setmetatable(L, -2);
*b = hb_face_reference_table(*f, *t);
return 1;
}
static int face_get_table_tags(lua_State *L) {
Face *f = (Face *)luaL_checkudata(L, 1, "harfbuzz.Face");
hb_tag_t tags[STATIC_ARRAY_SIZE];
unsigned int count = hb_face_get_table_tags(*f, 0, NULL, NULL);
if (count) {
unsigned int i = 0, offset = 0;
lua_createtable(L, count, 0);
do {
count = STATIC_ARRAY_SIZE;
hb_face_get_table_tags(*f, offset, &count, tags);
for (i = 0; i < count; i++) {
lua_pushnumber(L, offset + i + 1);
Tag *tp = (Tag *)lua_newuserdata(L, sizeof(*tp));
luaL_getmetatable(L, "harfbuzz.Tag");
lua_setmetatable(L, -2);
*tp = tags[i];
lua_rawset(L, -3);
}
offset += count;
} while (count == STATIC_ARRAY_SIZE);
} else {
lua_pushnil(L);
}
return 1;
}
static int face_ot_layout_get_script_tags(lua_State *L) {
Face *face = (Face *)luaL_checkudata(L, 1, "harfbuzz.Face");
Tag *table = (Tag *)luaL_checkudata(L, 2, "harfbuzz.Tag");
hb_tag_t tags[STATIC_ARRAY_SIZE];
unsigned int count = hb_ot_layout_table_get_script_tags(*face, *table, 0, NULL, NULL);
if (count) {
unsigned int i = 0, offset = 0;
lua_createtable(L, count, 0);
do {
count = STATIC_ARRAY_SIZE;
hb_ot_layout_table_get_script_tags(*face, *table, offset, &count, tags);
for (i = 0; i < count; i++) {
lua_pushnumber(L, offset + i + 1);
Tag *tp = (Tag *)lua_newuserdata(L, sizeof(*tp));
luaL_getmetatable(L, "harfbuzz.Tag");
lua_setmetatable(L, -2);
*tp = tags[i];
lua_rawset(L, -3);
}
offset += count;
} while (count == STATIC_ARRAY_SIZE);
} else {
lua_pushnil(L);
}
return 1;
}
static int face_ot_layout_get_language_tags(lua_State *L) {
Face *face = (Face *)luaL_checkudata(L, 1, "harfbuzz.Face");
Tag *table = (Tag *)luaL_checkudata(L, 2, "harfbuzz.Tag");
unsigned int script_index = (unsigned int) luaL_checkinteger(L, 3);
hb_tag_t tags[STATIC_ARRAY_SIZE];
unsigned int count = hb_ot_layout_script_get_language_tags(*face, *table, script_index, 0, NULL, NULL);
if (count) {
unsigned int i = 0, offset = 0;
lua_createtable(L, count, 0);
do {
count = STATIC_ARRAY_SIZE;
hb_ot_layout_script_get_language_tags(*face, *table, script_index, offset, &count, tags);
for (i = 0; i < count; i++) {
lua_pushnumber(L, offset + i + 1);
Tag *tp = (Tag *)lua_newuserdata(L, sizeof(*tp));
luaL_getmetatable(L, "harfbuzz.Tag");
lua_setmetatable(L, -2);
*tp = tags[i];
lua_rawset(L, -3);
}
offset += count;
} while (count == STATIC_ARRAY_SIZE);
} else {
lua_pushnil(L);
}
return 1;
}
static int face_ot_layout_get_feature_tags(lua_State *L) {
Face *face = (Face *)luaL_checkudata(L, 1, "harfbuzz.Face");
Tag *table = (Tag *)luaL_checkudata(L, 2, "harfbuzz.Tag");
unsigned int script_index = (unsigned int) luaL_checkinteger(L, 3);
unsigned int language_index = (unsigned int) luaL_checkinteger(L, 4);
hb_tag_t tags[STATIC_ARRAY_SIZE];
unsigned int count = hb_ot_layout_language_get_feature_tags(*face, *table, script_index, language_index, 0, NULL, NULL);
if (count) {
unsigned int i = 0, offset = 0;
lua_createtable(L, count, 0);
do {
count = STATIC_ARRAY_SIZE;
hb_ot_layout_language_get_feature_tags(*face, *table, script_index, language_index, offset, &count, tags);
for (i = 0; i < count; i++) {
lua_pushnumber(L, offset + i + 1);
Tag *tp = (Tag *)lua_newuserdata(L, sizeof(*tp));
luaL_getmetatable(L, "harfbuzz.Tag");
lua_setmetatable(L, -2);
*tp = tags[i];
lua_rawset(L, -3);
}
offset += count;
} while (count == STATIC_ARRAY_SIZE);
} else {
lua_pushnil(L);
}
return 1;
}
static int face_ot_layout_find_script(lua_State *L) {
Face *face = (Face *)luaL_checkudata(L, 1, "harfbuzz.Face");
Tag *table = (Tag *)luaL_checkudata(L, 2, "harfbuzz.Tag");
Tag *script = (Tag *)luaL_checkudata(L, 3, "harfbuzz.Tag");
unsigned int index = 0;
int found = hb_ot_layout_table_find_script(*face, *table, *script, &index);
lua_pushboolean(L, found);
lua_pushinteger(L, index);
return 2;
}
static int face_ot_layout_find_language(lua_State *L) {
Face *face = (Face *)luaL_checkudata(L, 1, "harfbuzz.Face");
Tag *table = (Tag *)luaL_checkudata(L, 2, "harfbuzz.Tag");
unsigned int script_index = (unsigned int) luaL_checkinteger(L, 3);
Tag *language = (Tag *)luaL_checkudata(L, 4, "harfbuzz.Tag");
unsigned int index = 0;
int found = hb_ot_layout_script_select_language(*face, *table, script_index, 1, &(*language), &index);
lua_pushboolean(L, found);
lua_pushinteger(L, index);
return 2;
}
static int face_ot_layout_find_feature(lua_State *L) {
Face *face = (Face *)luaL_checkudata(L, 1, "harfbuzz.Face");
Tag *table = (Tag *)luaL_checkudata(L, 2, "harfbuzz.Tag");
unsigned int script_index = (unsigned int) luaL_checkinteger(L, 3);
unsigned int language_index = (unsigned int) luaL_checkinteger(L, 4);
Tag *feature = (Tag *)luaL_checkudata(L, 5, "harfbuzz.Tag");
unsigned int index = 0;
int found = hb_ot_layout_language_find_feature(*face, *table, script_index, language_index, *feature, &index);
lua_pushboolean(L, found);
lua_pushinteger(L, index);
return 2;
}
static int face_collect_unicodes(lua_State *L) {
Face *f = (Face *)luaL_checkudata(L, 1, "harfbuzz.Face");
hb_set_t *codes = hb_set_create();
hb_face_collect_unicodes (*f, codes);
lua_createtable(L, hb_set_get_population(codes), 0);
if (!hb_set_is_empty(codes)) {
unsigned int i = 0;
hb_codepoint_t c = HB_SET_VALUE_INVALID;
while (hb_set_next(codes, &c)) {
lua_pushnumber(L, ++i);
lua_pushnumber(L, c);
lua_rawset(L, -3);
}
}
hb_set_destroy(codes);
return 1;
}
static int face_get_upem(lua_State *L) {
Face *f = (Face *)luaL_checkudata(L, 1, "harfbuzz.Face");
lua_pushinteger(L, hb_face_get_upem(*f));
return 1;
}
static int face_ot_color_has_palettes(lua_State *L) {
Face *f = (Face *)luaL_checkudata(L, 1, "harfbuzz.Face");
lua_pushboolean(L, hb_ot_color_has_palettes(*f));
return 1;
}
static int face_ot_color_palette_get_count(lua_State *L) {
Face *f = (Face *)luaL_checkudata(L, 1, "harfbuzz.Face");
lua_pushinteger(L, hb_ot_color_palette_get_count(*f));
return 1;
}
static int face_ot_color_palette_get_colors(lua_State *L) {
Face *f = (Face *)luaL_checkudata(L, 1, "harfbuzz.Face");
unsigned int index = (unsigned int) luaL_optinteger(L, 2, 1) - 1;
hb_color_t colors[STATIC_ARRAY_SIZE];
unsigned int count = hb_ot_color_palette_get_colors(*f, index, 0, NULL, NULL);
if (count) {
unsigned int i = 0, offset = 0;
lua_createtable(L, count, 0); // parent table
do {
count = STATIC_ARRAY_SIZE;
hb_ot_color_palette_get_colors(*f, index, offset, &count, colors);
for (i = 0; i < count; i++) {
hb_color_t color = colors[i];
lua_pushnumber(L, offset + i + 1); // 1-indexed key parent table
lua_createtable(L, 0, 4); // child table
lua_pushinteger(L, hb_color_get_red(color));
lua_setfield(L, -2, "red");
lua_pushinteger(L, hb_color_get_green(color));
lua_setfield(L, -2, "green");
lua_pushinteger(L, hb_color_get_blue(color));
lua_setfield(L, -2, "blue");
lua_pushinteger(L, hb_color_get_alpha(color));
lua_setfield(L, -2, "alpha");
lua_settable(L, -3); // Add child table at index i+1 to parent table
}
offset += count;
} while (count == STATIC_ARRAY_SIZE);
} else {
lua_pushnil(L);
}
return 1;
}
static int face_ot_color_has_layers(lua_State *L) {
Face *f = (Face *)luaL_checkudata(L, 1, "harfbuzz.Face");
lua_pushboolean(L, hb_ot_color_has_layers(*f));
return 1;
}
static int face_ot_color_glyph_get_layers(lua_State *L) {
Face *f = (Face *)luaL_checkudata(L, 1, "harfbuzz.Face");
hb_codepoint_t gid = (hb_codepoint_t) luaL_checkinteger(L, 2);
hb_ot_color_layer_t layers[STATIC_ARRAY_SIZE];
unsigned int count = hb_ot_color_glyph_get_layers(*f, gid, 0, NULL, NULL);
if (count) {
unsigned int i = 0, offset = 0;
lua_createtable(L, count, 0); // parent table
do {
count = STATIC_ARRAY_SIZE;
hb_ot_color_glyph_get_layers(*f, gid, offset, &count, layers);
for (i = 0; i < count; i++) {
hb_ot_color_layer_t layer = layers[i];
unsigned int color_index = layer.color_index;
if (color_index != 0xFFFF)
color_index++; // make it 1-indexed
lua_pushnumber(L, offset + i + 1); // 1-indexed key parent table
lua_createtable(L, 0, 2); // child table
lua_pushinteger(L, layer.glyph);
lua_setfield(L, -2, "glyph");
lua_pushinteger(L, color_index);
lua_setfield(L, -2, "color_index");
lua_settable(L, -3); // Add child table at index i+1 to parent table
}
offset += count;
} while (count == STATIC_ARRAY_SIZE);
} else {
lua_pushnil(L);
}
return 1;
}
static int face_ot_color_has_png(lua_State *L) {
Face *f = (Face *)luaL_checkudata(L, 1, "harfbuzz.Face");
lua_pushboolean(L, hb_ot_color_has_png(*f));
return 1;
}
static int face_ot_color_has_svg(lua_State *L) {
Face *f = (Face *)luaL_checkudata(L, 1, "harfbuzz.Face");
lua_pushboolean(L, hb_ot_color_has_svg(*f));
return 1;
}
static int face_ot_color_glyph_get_svg(lua_State *L) {
Face *f = (Face *)luaL_checkudata(L, 1, "harfbuzz.Face");
hb_codepoint_t gid = (hb_codepoint_t) luaL_checkinteger(L, 2);
hb_blob_t* blob = hb_ot_color_glyph_reference_svg(*f, gid);
if (hb_blob_get_length(blob) != 0) {
Blob *b = (Blob *)lua_newuserdata(L, sizeof(*b));
luaL_getmetatable(L, "harfbuzz.Blob");
lua_setmetatable(L, -2);
*b = blob;
} else {
lua_pushnil(L);
}
return 1;
}
static int face_destroy(lua_State *L) {
Face *f = (Face *)luaL_checkudata(L, 1, "harfbuzz.Face");
hb_face_destroy(*f);
return 0;
}
static const struct luaL_Reg face_methods[] = {
{ "__gc", face_destroy },
{ "collect_unicodes", face_collect_unicodes },
{ "get_glyph_count", face_get_glyph_count },
{ "get_name", face_get_name },
{ "get_table", face_get_table },
{ "get_table_tags", face_get_table_tags },
{ "get_upem", face_get_upem },
{ "ot_color_has_palettes", face_ot_color_has_palettes },
{ "ot_color_palette_get_count", face_ot_color_palette_get_count },
{ "ot_color_palette_get_colors", face_ot_color_palette_get_colors },
{ "ot_color_has_layers", face_ot_color_has_layers },
{ "ot_color_glyph_get_layers", face_ot_color_glyph_get_layers },
{ "ot_color_has_png", face_ot_color_has_png },
{ "ot_color_has_svg", face_ot_color_has_svg },
{ "ot_color_glyph_get_svg", face_ot_color_glyph_get_svg },
{ "ot_layout_get_script_tags", face_ot_layout_get_script_tags },
{ "ot_layout_get_language_tags", face_ot_layout_get_language_tags },
{ "ot_layout_get_feature_tags", face_ot_layout_get_feature_tags },
{ "ot_layout_find_script", face_ot_layout_find_script },
{ "ot_layout_find_language", face_ot_layout_find_language },
{ "ot_layout_find_feature", face_ot_layout_find_feature },
{ NULL, NULL }
};
static const struct luaL_Reg face_functions[] = {
{ "new", face_new },
{ "new_from_blob", face_new_from_blob },
{ NULL, NULL }
};
int register_face(lua_State *L) {
return register_class(L, "harfbuzz.Face", face_methods, face_functions, NULL);
}

View file

@ -0,0 +1,110 @@
// harfbuzz.Feature
#include "luaharfbuzz.h"
static int feature_new(lua_State *L) {
Feature f;
const char *feature = luaL_checkstring(L, 1);
if (hb_feature_from_string(feature, -1, &f)) {
Feature *fp = (Feature *)lua_newuserdata(L, sizeof(*fp));
luaL_getmetatable(L, "harfbuzz.Feature");
lua_setmetatable(L, -2);
*fp = f;
} else {
lua_pushnil(L);
}
return 1;
}
static int feature_to_string(lua_State *L) {
Feature* f = (Feature *)luaL_checkudata(L, 1, "harfbuzz.Feature");
char feature[128];
hb_feature_to_string(f, feature, 128);
lua_pushstring(L, feature);
return 1;
}
static const char *feature_tag_ptr;
static const char *feature_value_ptr;
static const char *feature_start_ptr;
static const char *feature_end_ptr;
static int feature_index(lua_State *L) {
Feature* f = (Feature *)luaL_checkudata(L, 1, "harfbuzz.Feature");
const char *key = lua_tostring(L, 2);
if (key == feature_tag_ptr) {
Tag *tag = (Tag *)lua_newuserdata(L, sizeof(*tag));
luaL_getmetatable(L, "harfbuzz.Tag");
lua_setmetatable(L, -2);
*tag = f->tag;
} else if (key == feature_value_ptr) {
lua_pushinteger(L, f->value);
} else if (key == feature_start_ptr) {
if (f->start == HB_FEATURE_GLOBAL_START)
lua_pushnil(L);
else
lua_pushinteger(L, f->start);
} else if (key == feature_end_ptr) {
if (f->end == HB_FEATURE_GLOBAL_END)
lua_pushnil(L);
else
lua_pushinteger(L, f->end);
} else {
lua_pushnil(L);
}
return 1;
}
static int feature_newindex(lua_State *L) {
Feature* f = (Feature *)luaL_checkudata(L, 1, "harfbuzz.Feature");
const char *key = lua_tostring(L, 2);
if (key == feature_tag_ptr) {
f->tag = *(Tag *)luaL_checkudata(L, 3, "harfbuzz.Tag");
} else if (key == feature_value_ptr) {
f->value = luaL_checkinteger(L, 3);
} else if (key == feature_start_ptr) {
if (lua_toboolean(L, 3))
f->start = luaL_checkinteger(L, 3);
else
f->start = HB_FEATURE_GLOBAL_START;
} else if (key == feature_end_ptr) {
if (lua_toboolean(L, 3))
f->end = luaL_checkinteger(L, 3);
else
f->end = HB_FEATURE_GLOBAL_END;
}
return 0;
}
static const struct luaL_Reg feature_methods[] = {
{ "__index", feature_index },
{ "__newindex", feature_newindex },
{ "__tostring", feature_to_string },
{ NULL, NULL },
};
static const struct luaL_Reg feature_functions[] = {
{ "new", feature_new },
{ NULL, NULL }
};
int register_feature(lua_State *L) {
lua_pushliteral(L, "tag");
feature_tag_ptr = lua_tostring(L, -1);
(void) luaL_ref (L, LUA_REGISTRYINDEX);
lua_pushliteral(L, "value");
feature_value_ptr = lua_tostring(L, -1);
(void) luaL_ref (L, LUA_REGISTRYINDEX);
lua_pushliteral(L, "start");
feature_start_ptr = lua_tostring(L, -1);
(void) luaL_ref (L, LUA_REGISTRYINDEX);
lua_pushliteral(L, "_end"); /* _end instead of end to avoid Lua keyword */
feature_end_ptr = lua_tostring(L, -1);
(void) luaL_ref (L, LUA_REGISTRYINDEX);
return register_class(L, "harfbuzz.Feature", feature_methods, feature_functions, NULL);
}

View file

@ -0,0 +1,218 @@
#include "luaharfbuzz.h"
static int font_new(lua_State *L) {
Font *f;
Face *face = luaL_checkudata(L, 1, "harfbuzz.Face");
f = (Font *)lua_newuserdata(L, sizeof(*f));
luaL_getmetatable(L, "harfbuzz.Font");
lua_setmetatable(L, -2);
*f = hb_font_create(*face);
// Set default scale to be the face's upem value
unsigned int upem = hb_face_get_upem(*face);
hb_font_set_scale(*f, upem, upem);
// Set shaping functions to OpenType functions
hb_ot_font_set_funcs(*f);
return 1;
}
static int font_set_scale(lua_State *L) {
Font *f = (Font *)luaL_checkudata(L, 1, "harfbuzz.Font");
int x_scale = luaL_checkinteger(L, 2);
int y_scale = luaL_checkinteger(L, 3);
hb_font_set_scale(*f, x_scale, y_scale);
return 0;
}
static int font_get_scale(lua_State *L) {
Font *f = (Font *)luaL_checkudata(L, 1, "harfbuzz.Font");
int x_scale, y_scale;
hb_font_get_scale(*f, &x_scale, &y_scale);
lua_pushinteger(L, x_scale);
lua_pushinteger(L, y_scale);
return 2;
}
static int font_get_h_extents(lua_State *L) {
Font *f = (Font *)luaL_checkudata(L, 1, "harfbuzz.Font");
hb_font_extents_t extents;
if (hb_font_get_h_extents(*f, &extents)) {
lua_createtable(L, 0, 3);
lua_pushnumber(L, extents.ascender);
lua_setfield(L, -2, "ascender");
lua_pushnumber(L, extents.descender);
lua_setfield(L, -2, "descender");
lua_pushnumber(L, extents.line_gap);
lua_setfield(L, -2, "line_gap");
} else {
lua_pushnil(L);
}
return 1;
}
static int font_get_v_extents(lua_State *L) {
Font *f = (Font *)luaL_checkudata(L, 1, "harfbuzz.Font");
hb_font_extents_t extents;
if (hb_font_get_v_extents(*f, &extents)) {
lua_createtable(L, 0, 3);
lua_pushnumber(L, extents.ascender);
lua_setfield(L, -2, "ascender");
lua_pushnumber(L, extents.descender);
lua_setfield(L, -2, "descender");
lua_pushnumber(L, extents.line_gap);
lua_setfield(L, -2, "line_gap");
} else {
lua_pushnil(L);
}
return 1;
}
static int font_get_glyph_extents(lua_State *L) {
Font *f = (Font *)luaL_checkudata(L, 1, "harfbuzz.Font");
hb_codepoint_t glyph = luaL_checkinteger(L, 2);
hb_glyph_extents_t extents;
if (hb_font_get_glyph_extents(*f, glyph, &extents)) {
lua_createtable(L, 0, 4);
lua_pushnumber(L, extents.x_bearing);
lua_setfield(L, -2, "x_bearing");
lua_pushnumber(L, extents.y_bearing);
lua_setfield(L, -2, "y_bearing");
lua_pushnumber(L, extents.width);
lua_setfield(L, -2, "width");
lua_pushnumber(L, extents.height);
lua_setfield(L, -2, "height");
} else {
lua_pushnil(L);
}
return 1;
}
static int font_get_glyph_name(lua_State *L) {
Font *f = (Font *)luaL_checkudata(L, 1, "harfbuzz.Font");
hb_codepoint_t glyph = luaL_checkinteger(L, 2);
#define NAME_LEN 128
char name[NAME_LEN];
if (hb_font_get_glyph_name(*f, glyph, name, NAME_LEN))
lua_pushstring(L, name);
else
lua_pushnil(L);
#undef NAME_LEN
return 1;
}
static int font_get_glyph_from_name(lua_State *L) {
Font *f = (Font *)luaL_checkudata(L, 1, "harfbuzz.Font");
const char *name = luaL_checkstring(L, 2);
hb_codepoint_t glyph;
if (hb_font_get_glyph_from_name(*f, name, -1, &glyph))
lua_pushinteger(L, glyph);
else
lua_pushnil(L);
return 1;
}
static int font_get_glyph_h_advance(lua_State *L) {
Font *f = (Font *)luaL_checkudata(L, 1, "harfbuzz.Font");
hb_codepoint_t glyph = luaL_checkinteger(L, 2);
lua_pushinteger(L, hb_font_get_glyph_h_advance(*f, glyph));
return 1;
}
static int font_get_glyph_v_advance(lua_State *L) {
Font *f = (Font *)luaL_checkudata(L, 1, "harfbuzz.Font");
hb_codepoint_t glyph = luaL_checkinteger(L, 2);
lua_pushinteger(L, hb_font_get_glyph_v_advance(*f, glyph));
return 1;
}
static int font_get_nominal_glyph(lua_State *L) {
Font *f = (Font *)luaL_checkudata(L, 1, "harfbuzz.Font");
hb_codepoint_t uni = luaL_checkinteger(L, 2);
hb_codepoint_t glyph;
if (hb_font_get_nominal_glyph(*f, uni, &glyph))
lua_pushinteger(L, glyph);
else
lua_pushnil(L);
return 1;
}
static int font_destroy(lua_State *L) {
Font *f = (Font *)luaL_checkudata(L, 1, "harfbuzz.Font");
hb_font_destroy(*f);
return 0;
}
static int font_ot_color_glyph_get_png(lua_State *L) {
Font *f = (Font *)luaL_checkudata(L, 1, "harfbuzz.Font");
hb_codepoint_t gid = (hb_codepoint_t) luaL_checkinteger(L, 2);
hb_blob_t* blob = hb_ot_color_glyph_reference_png(*f, gid);
if (hb_blob_get_length(blob) != 0) {
Blob *b = (Blob *)lua_newuserdata(L, sizeof(*b));
luaL_getmetatable(L, "harfbuzz.Blob");
lua_setmetatable(L, -2);
*b = blob;
} else {
lua_pushnil(L);
}
return 1;
}
static const struct luaL_Reg font_methods[] = {
{ "__gc", font_destroy },
{ "set_scale", font_set_scale },
{ "get_scale", font_get_scale },
{ "get_h_extents", font_get_h_extents },
{ "get_v_extents", font_get_v_extents },
{ "get_glyph_extents", font_get_glyph_extents },
{ "get_glyph_name", font_get_glyph_name },
{ "get_glyph_from_name", font_get_glyph_from_name },
{ "get_glyph_h_advance", font_get_glyph_h_advance },
{ "get_glyph_v_advance", font_get_glyph_v_advance },
{ "get_nominal_glyph", font_get_nominal_glyph },
{ "ot_color_glyph_get_png", font_ot_color_glyph_get_png },
{ NULL, NULL }
};
static const struct luaL_Reg font_functions[] = {
{ "new", font_new },
{ NULL, NULL }
};
int register_font(lua_State *L) {
return register_class(L, "harfbuzz.Font", font_methods, font_functions, NULL);
}

View file

@ -0,0 +1,49 @@
// harfbuzz.Feature
#include "luaharfbuzz.h"
static int language_new(lua_State *L) {
Language *l;
l = (Language *)lua_newuserdata(L, sizeof(*l));
luaL_getmetatable(L, "harfbuzz.Language");
lua_setmetatable(L, -2);
if (lua_gettop(L) == 1 || lua_isnil(L, -2))
*l = HB_LANGUAGE_INVALID;
else
*l = hb_language_from_string(luaL_checkstring(L, -2), -1);
return 1;
}
static int language_to_string(lua_State *L) {
Language* l = (Language *)luaL_checkudata(L, 1, "harfbuzz.Language");
const char *s = hb_language_to_string(*l);
lua_pushstring(L, s ? s : "");
return 1;
}
static int language_equals(lua_State *L) {
Language* lhs = (Language *)luaL_checkudata(L, 1, "harfbuzz.Language");
Language* rhs = (Language *)luaL_checkudata(L, 2, "harfbuzz.Language");
lua_pushboolean(L, *lhs == *rhs);
return 1;
}
static const struct luaL_Reg language_methods[] = {
{ "__tostring", language_to_string },
{ "__eq", language_equals },
{ NULL, NULL }
};
static const struct luaL_Reg language_functions[] = {
{ "new", language_new },
{ NULL, NULL }
};
int register_language(lua_State *L) {
return register_class(L, "harfbuzz.Language", language_methods, language_functions, NULL);
}

View file

@ -0,0 +1,102 @@
#include "luaharfbuzz.h"
static int shape_full (lua_State *L) {
Font *font = (Font *)luaL_checkudata(L, 1, "harfbuzz.Font");
Buffer *buf = (Buffer *)luaL_checkudata(L, 2, "harfbuzz.Buffer");
luaL_checktype(L, 3, LUA_TTABLE);
luaL_checktype(L, 4, LUA_TTABLE);
unsigned int num_features = lua_rawlen(L, 3);
Feature *features = (Feature *) malloc (num_features * sizeof(hb_feature_t));
for (unsigned int i = 0; i != num_features; ++i) {
lua_geti(L, 3, i + 1);
Feature* f = (Feature *)luaL_checkudata(L, -1, "harfbuzz.Feature");
features[i] = *f;
lua_pop(L, 1);
}
const char **shapers = NULL;
size_t num_shapers = lua_rawlen(L, 4);
if (num_shapers) {
shapers = (const char**) calloc (num_shapers + 1, sizeof(char*));
for (unsigned int i = 0; i != num_shapers; ++i) {
lua_geti(L, 4, i + 1);
shapers[i] = luaL_checkstring(L, -1);
lua_pop(L, 1);
}
}
// Shape text
lua_pushboolean(L, hb_shape_full(*font, *buf, features, num_features, shapers));
free(features);
free(shapers);
return 1;
}
static int version (lua_State *L) {
lua_pushstring(L, hb_version_string());
return 1;
}
static int list_shapers (lua_State *L) {
const char **shaper_list = hb_shape_list_shapers ();
int i = 0;
for (; *shaper_list; shaper_list++) {
i++;
lua_pushstring(L, *shaper_list);
}
return i;
}
static const struct luaL_Reg lib_table [] = {
{"shape_full", shape_full},
{"version", version},
{"shapers", list_shapers},
{NULL, NULL}
};
int luaopen_luaharfbuzz (lua_State *L) {
lua_newtable(L);
register_blob(L);
lua_setfield(L, -2, "Blob");
register_face(L);
lua_setfield(L, -2, "Face");
register_font(L);
lua_setfield(L, -2, "Font");
register_buffer(L);
lua_setfield(L, -2, "Buffer");
register_feature(L);
lua_setfield(L, -2, "Feature");
register_tag(L);
lua_setfield(L, -2, "Tag");
register_script(L);
lua_setfield(L, -2, "Script");
register_direction(L);
lua_setfield(L, -2, "Direction");
register_language(L);
lua_setfield(L, -2, "Language");
register_ot(L);
lua_setfield(L, -2, "ot");
register_unicode(L);
lua_setfield(L, -2, "unicode");
luaL_setfuncs(L, lib_table, 0);
return 1;
}

View file

@ -0,0 +1,39 @@
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <hb.h>
#include <hb-ot.h>
#include <string.h>
#include <lua.h>
#include <lauxlib.h>
#include <lualib.h>
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 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);
int register_blob(lua_State *L);
int register_face(lua_State *L);
int register_font(lua_State *L);
int register_buffer(lua_State *L);
int register_feature(lua_State *L);
int register_tag(lua_State *L);
int register_script(lua_State *L);
int register_direction(lua_State *L);
int register_language(lua_State *L);
int register_ot(lua_State *L);
int register_unicode(lua_State *L);

View file

@ -0,0 +1,47 @@
#include "luaharfbuzz.h"
static const struct luahb_constant_t ot_constants[] = {
{ "NAME_ID_COPYRIGHT", HB_OT_NAME_ID_COPYRIGHT },
{ "NAME_ID_FONT_FAMILY", HB_OT_NAME_ID_FONT_FAMILY },
{ "NAME_ID_FONT_SUBFAMILY", HB_OT_NAME_ID_FONT_SUBFAMILY },
{ "NAME_ID_UNIQUE_ID", HB_OT_NAME_ID_UNIQUE_ID },
{ "NAME_ID_FULL_NAME", HB_OT_NAME_ID_FULL_NAME },
{ "NAME_ID_VERSION_STRING", HB_OT_NAME_ID_VERSION_STRING },
{ "NAME_ID_POSTSCRIPT_NAME", HB_OT_NAME_ID_POSTSCRIPT_NAME },
{ "NAME_ID_TRADEMARK", HB_OT_NAME_ID_TRADEMARK },
{ "NAME_ID_MANUFACTURER", HB_OT_NAME_ID_MANUFACTURER },
{ "NAME_ID_DESIGNER", HB_OT_NAME_ID_DESIGNER },
{ "NAME_ID_DESCRIPTION", HB_OT_NAME_ID_DESCRIPTION },
{ "NAME_ID_VENDOR_URL", HB_OT_NAME_ID_VENDOR_URL },
{ "NAME_ID_DESIGNER_URL", HB_OT_NAME_ID_DESIGNER_URL },
{ "NAME_ID_LICENSE", HB_OT_NAME_ID_LICENSE },
{ "NAME_ID_LICENSE_URL", HB_OT_NAME_ID_LICENSE_URL },
{ "NAME_ID_TYPOGRAPHIC_FAMILY", HB_OT_NAME_ID_TYPOGRAPHIC_FAMILY },
{ "NAME_ID_TYPOGRAPHIC_SUBFAMILY", HB_OT_NAME_ID_TYPOGRAPHIC_SUBFAMILY },
{ "NAME_ID_MAC_FULL_NAME", HB_OT_NAME_ID_MAC_FULL_NAME },
{ "NAME_ID_SAMPLE_TEXT", HB_OT_NAME_ID_SAMPLE_TEXT },
{ "NAME_ID_CID_FINDFONT_NAME", HB_OT_NAME_ID_CID_FINDFONT_NAME },
{ "NAME_ID_WWS_FAMILY", HB_OT_NAME_ID_WWS_FAMILY },
{ "NAME_ID_WWS_SUBFAMILY", HB_OT_NAME_ID_WWS_SUBFAMILY },
{ "NAME_ID_LIGHT_BACKGROUND", HB_OT_NAME_ID_LIGHT_BACKGROUND },
{ "NAME_ID_DARK_BACKGROUND", HB_OT_NAME_ID_DARK_BACKGROUND },
{ "NAME_ID_VARIATIONS_PS_PREFIX", HB_OT_NAME_ID_VARIATIONS_PS_PREFIX },
{ "NAME_ID_INVALID", HB_OT_NAME_ID_INVALID },
{ "LAYOUT_NO_SCRIPT_INDEX", HB_OT_LAYOUT_NO_SCRIPT_INDEX },
{ "LAYOUT_NO_FEATURE_INDEX", HB_OT_LAYOUT_NO_FEATURE_INDEX },
{ "LAYOUT_DEFAULT_LANGUAGE_INDEX", HB_OT_LAYOUT_DEFAULT_LANGUAGE_INDEX },
{ "LAYOUT_NO_VARIATIONS_INDEX", HB_OT_LAYOUT_NO_VARIATIONS_INDEX },
{ NULL, 0 }
};
static const struct luaL_Reg ot_methods[] = {
{ NULL, NULL }
};
static const struct luaL_Reg ot_functions[] = {
{ NULL, NULL }
};
int register_ot(lua_State *L) {
return register_class(L, "harfbuzz.ot", ot_methods, ot_functions, ot_constants);
}

View file

@ -0,0 +1,71 @@
#include "luaharfbuzz.h"
static int new_script_from_string(lua_State *L) {
Script *sp = (Script *)lua_newuserdata(L, sizeof(*sp));
luaL_getmetatable(L, "harfbuzz.Script");
lua_setmetatable(L, -2);
if (lua_gettop(L) == 1 || lua_isnil(L, -2))
*sp = HB_SCRIPT_INVALID;
else
*sp = hb_script_from_string(luaL_checkstring(L, -2), -1);
return 1;
}
static int new_script_from_tag(lua_State *L) {
Tag* tp = (Tag *)luaL_checkudata(L, 1, "harfbuzz.Tag");
Script *sp = (Script *)lua_newuserdata(L, sizeof(*sp));
luaL_getmetatable(L, "harfbuzz.Script");
lua_setmetatable(L, -2);
*sp = hb_script_from_iso15924_tag(*tp);
return 1;
}
static int script_to_string(lua_State *L) {
Script *script = (Script *)luaL_checkudata(L, 1, "harfbuzz.Script");
char s[5];
hb_tag_to_string(hb_script_to_iso15924_tag(*script), s);
s[4] = '\0';
lua_pushstring(L, s);
return 1;
}
static int script_to_tag(lua_State *L) {
Script *script = (Script *)luaL_checkudata(L, 1, "harfbuzz.Script");
Tag *tp = (Tag *)lua_newuserdata(L, sizeof(*tp));
luaL_getmetatable(L, "harfbuzz.Tag");
lua_setmetatable(L, -2);
*tp = hb_script_to_iso15924_tag(*script);
return 1;
}
static int script_equals(lua_State *L) {
Script* lhs = (Script *)luaL_checkudata(L, 1, "harfbuzz.Script");
Script* rhs = (Script *)luaL_checkudata(L, 2, "harfbuzz.Script");
lua_pushboolean(L, *lhs == *rhs);
return 1;
}
static const struct luaL_Reg script_methods[] = {
{ "__tostring", script_to_string },
{ "__eq", script_equals },
{ "to_iso15924_tag", script_to_tag },
{ NULL, NULL }
};
static const struct luaL_Reg script_functions[] = {
{ "new", new_script_from_string },
{ "from_iso15924_tag", new_script_from_tag },
{ NULL, NULL }
};
int register_script(lua_State *L) {
return register_class(L, "harfbuzz.Script", script_methods, script_functions, NULL);
}

View file

@ -0,0 +1,50 @@
// harfbuzz.Feature
#include "luaharfbuzz.h"
static int tag_new(lua_State *L) {
Tag *t;
t = (Tag *)lua_newuserdata(L, sizeof(*t));
luaL_getmetatable(L, "harfbuzz.Tag");
lua_setmetatable(L, -2);
if (lua_gettop(L) == 1 || lua_isnil(L, -2))
*t = HB_TAG_NONE;
else
*t = hb_tag_from_string(luaL_checkstring(L, -2), -1);
return 1;
}
static int tag_to_string(lua_State *L) {
Tag* t = (Tag *)luaL_checkudata(L, 1, "harfbuzz.Tag");
char tag[5];
hb_tag_to_string(*t, tag);
tag[4] = '\0';
lua_pushstring(L, tag);
return 1;
}
static int tag_equals(lua_State *L) {
Tag* lhs = (Tag *)luaL_checkudata(L, 1, "harfbuzz.Tag");
Tag* rhs = (Tag *)luaL_checkudata(L, 2, "harfbuzz.Tag");
lua_pushboolean(L, *lhs == *rhs);
return 1;
}
static const struct luaL_Reg tag_methods[] = {
{ "__tostring", tag_to_string },
{ "__eq", tag_equals },
{ NULL, NULL }
};
static const struct luaL_Reg tag_functions[] = {
{ "new", tag_new },
{ NULL, NULL }
};
int register_tag(lua_State *L) {
return register_class(L, "harfbuzz.Tag", tag_methods, tag_functions, NULL);
}

View file

@ -0,0 +1,33 @@
This is LuaHBTeX, Version 1.11.2 (TeX Live 2020/dev) (format=luahbtex 2019.12.5) 11 DEC 2019 21:17
restricted system commands enabled.
**\relax
*\directlua{print(luaharfbuzz.Tag.new"ab ")}
*\directlua{print(luaharfbuzz.Tag.new"ab " .. 'c')}
[\directlua]:1: attempt to concatenate a harfbuzz.Tag value
stack traceback:
[\directlua]:1: in main chunk.
<*> ...ctlua{print(luaharfbuzz.Tag.new"ab " .. 'c')}
? \directlua{print(tostring(luaharfbuzz.Tag.new"ab ") .. 'c')}
Type <return> to proceed, S to scroll future error messages,
R to run without stopping, Q to run quietly,
I to insert something,
1 or ... or 9 to ignore the next 1 to 9 tokens of input,
H for help, X to quit.
?
*\directlua{print(tostring(luaharfbuzz.Tag.new"ab ") .. 'c')}
*directlua{print(tostring(luaharfbuzz.Tag.new"ab") .. 'c')}
*\directlua{print(tostring(luaharfbuzz.Tag.new"ab") .. 'c')}
*
! Emergency stop.
<*> ...int(tostring(luaharfbuzz.Tag.new"ab") .. 'c')}
End of file on the terminal!
! ==> Fatal error occurred, no output PDF file produced!

View file

@ -0,0 +1,22 @@
#include "luaharfbuzz.h"
static int script(lua_State *L) {
hb_codepoint_t c = (hb_codepoint_t) luaL_checkinteger(L, -1);
Script *sp = (Script *)lua_newuserdata(L, sizeof(*sp));
luaL_getmetatable(L, "harfbuzz.Script");
lua_setmetatable(L, -2);
*sp = hb_unicode_script(hb_unicode_funcs_get_default(), c);
return 1;
}
static const struct luaL_Reg unicode_functions[] = {
{ "script", script },
{ NULL, NULL }
};
int register_unicode(lua_State *L) {
luaL_newlib(L, unicode_functions);
return 1;
}