#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); }