luametalatex-c/luaharfbuzz/src/luaharfbuzz/face.c

467 lines
14 KiB
C

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