/** * hb_shape_full: * @font: an #hb_font_t to use for shaping * @buffer: an #hb_buffer_t to shape * @features: (array length=num_features) (allow-none): an array of user * specified #hb_feature_t or %NULL * @num_features: the length of @features array * @shaper_list: (array zero-terminated=1) (allow-none): a %NULL-terminated * array of shapers to use or %NULL * * See hb_shape() for details. If @shaper_list is not %NULL, the specified * shapers will be used in the given order, otherwise the default shapers list * will be used. * * Return value: %FALSE if all shapers failed, %TRUE otherwise * * Since: 0.9.2 **/ hb_bool_t hb_shape_full (hb_font_t *font, hb_buffer_t *buffer, const hb_feature_t *features, unsigned int num_features, const char * const *shaper_list) { hb_shape_plan_t *shape_plan = hb_shape_plan_create_cached (font->face, &buffer->props, features, num_features, shaper_list); hb_bool_t res = hb_shape_plan_execute (shape_plan, font, buffer, features, num_features); hb_shape_plan_destroy (shape_plan); if (res) buffer->content_type = HB_BUFFER_CONTENT_TYPE_GLYPHS; return res; }
int shape (lua_State *L) { const char * text = luaL_checkstring(L, 1); FT_Face face = lua_touserdata(L, 2); const char * script = luaL_checkstring(L, 3); const char * direction_s = luaL_checkstring(L, 4); const char * lang = luaL_checkstring(L, 5); double point_size = luaL_checknumber(L, 6); const char * featurestring = luaL_checkstring(L, 7); hb_segment_properties_t segment_props; hb_shape_plan_t *shape_plan; hb_direction_t direction; hb_feature_t* features; int nFeatures = 0; unsigned int glyph_count = 0; hb_font_t *hb_ft_font; hb_face_t *hb_ft_face; hb_buffer_t *buf; hb_glyph_info_t *glyph_info; hb_glyph_position_t *glyph_pos; unsigned int j; features = scan_feature_string(featurestring, &nFeatures); if (!strcasecmp(direction_s,"RTL")) direction = HB_DIRECTION_RTL; else if (!strcasecmp(direction_s,"TTB")) direction = HB_DIRECTION_TTB; else direction = HB_DIRECTION_LTR; hb_ft_font = hb_ft_font_create(face, NULL); hb_face_t* hbFace = hb_font_get_face(hb_ft_font); buf = hb_buffer_create(); hb_buffer_add_utf8(buf, text, strlen(text), 0, strlen(text)); hb_buffer_set_script(buf, hb_tag_from_string(script, strlen(script))); hb_buffer_set_direction(buf, direction); hb_buffer_set_language(buf, hb_language_from_string(lang,strlen(lang))); hb_buffer_guess_segment_properties(buf); hb_buffer_get_segment_properties(buf, &segment_props); shape_plan = hb_shape_plan_create_cached(hbFace, &segment_props, features, nFeatures, NULL); int res = hb_shape_plan_execute(shape_plan, hb_ft_font, buf, features, nFeatures); glyph_info = hb_buffer_get_glyph_infos(buf, &glyph_count); glyph_pos = hb_buffer_get_glyph_positions(buf, &glyph_count); lua_checkstack(L, glyph_count); for (j = 0; j < glyph_count; ++j) { char namebuf[255]; box glyph_extents = { 0.0, 0.0, 0.0 }; calculate_extents(&glyph_extents, glyph_info[j], glyph_pos[j], face, point_size, direction); lua_newtable(L); lua_pushstring(L, "name"); FT_Get_Glyph_Name( face, glyph_info[j].codepoint, namebuf, 255 ); lua_pushstring(L, namebuf); lua_settable(L, -3); if (direction != HB_DIRECTION_TTB) { /* XXX */ if (glyph_pos[j].x_offset) { lua_pushstring(L, "x_offset"); lua_pushnumber(L, glyph_pos[j].x_offset / 64.0); lua_settable(L, -3); } if (glyph_pos[j].y_offset) { lua_pushstring(L, "y_offset"); lua_pushnumber(L, glyph_pos[j].y_offset / 64.0); lua_settable(L, -3); } } lua_pushstring(L, "codepoint"); lua_pushinteger(L, glyph_info[j].codepoint); lua_settable(L, -3); lua_pushstring(L, "width"); lua_pushnumber(L, glyph_extents.width); lua_settable(L, -3); lua_pushstring(L, "height"); lua_pushnumber(L, glyph_extents.height); lua_settable(L, -3); lua_pushstring(L, "depth"); lua_pushnumber(L, glyph_extents.depth); lua_settable(L, -3); } /* Cleanup */ hb_buffer_destroy(buf); hb_font_destroy(hb_ft_font); hb_shape_plan_destroy(shape_plan); free(features); return glyph_count; }
int shape (lua_State *L) { size_t font_l; const char * text = luaL_checkstring(L, 1); const char * font_s = luaL_checklstring(L, 2, &font_l); unsigned int font_index = luaL_checknumber(L, 3); const char * script = luaL_checkstring(L, 4); const char * direction_s = luaL_checkstring(L, 5); const char * lang = luaL_checkstring(L, 6); double point_size = luaL_checknumber(L, 7); const char * featurestring = luaL_checkstring(L, 8); hb_segment_properties_t segment_props; hb_shape_plan_t *shape_plan; hb_direction_t direction; hb_feature_t* features; int nFeatures = 0; unsigned int glyph_count = 0; hb_font_t *hbFont; hb_buffer_t *buf; hb_glyph_info_t *glyph_info; hb_glyph_position_t *glyph_pos; unsigned int j; features = scan_feature_string(featurestring, &nFeatures); if (!strcasecmp(direction_s,"RTL")) direction = HB_DIRECTION_RTL; else if (!strcasecmp(direction_s,"TTB")) direction = HB_DIRECTION_TTB; else direction = HB_DIRECTION_LTR; hb_blob_t* blob = hb_blob_create (font_s, font_l, HB_MEMORY_MODE_WRITABLE, (void*)font_s, NULL); hb_face_t* hbFace = hb_face_create (blob, font_index); hbFont = hb_font_create (hbFace); unsigned int upem = hb_face_get_upem(hbFace); hb_font_set_scale(hbFont, upem, upem); /* Harfbuzz's support for OT fonts is great, but there's currently no support for CFF fonts, so downgrade to Freetype for those. */ if (strncmp(font_s, "OTTO", 4) == 0) { hb_ft_font_set_funcs(hbFont); } else { hb_ot_font_set_funcs(hbFont); } buf = hb_buffer_create(); hb_buffer_add_utf8(buf, text, strlen(text), 0, strlen(text)); hb_buffer_set_script(buf, hb_tag_from_string(script, strlen(script))); hb_buffer_set_direction(buf, direction); hb_buffer_set_language(buf, hb_language_from_string(lang,strlen(lang))); hb_buffer_guess_segment_properties(buf); hb_buffer_get_segment_properties(buf, &segment_props); shape_plan = hb_shape_plan_create_cached(hbFace, &segment_props, features, nFeatures, NULL); int res = hb_shape_plan_execute(shape_plan, hbFont, buf, features, nFeatures); if (direction == HB_DIRECTION_RTL) { hb_buffer_reverse(buf); /* URGH */ } glyph_info = hb_buffer_get_glyph_infos(buf, &glyph_count); glyph_pos = hb_buffer_get_glyph_positions(buf, &glyph_count); lua_checkstack(L, glyph_count); for (j = 0; j < glyph_count; ++j) { char namebuf[255]; hb_glyph_extents_t extents = {0,0,0,0}; hb_font_get_glyph_extents(hbFont, glyph_info[j].codepoint, &extents); lua_newtable(L); lua_pushstring(L, "name"); hb_font_get_glyph_name( hbFont, glyph_info[j].codepoint, namebuf, 255 ); lua_pushstring(L, namebuf); lua_settable(L, -3); /* We don't apply x-offset and y-offsets for TTB, which is arguably a bug. We should. The reason we don't is that Harfbuzz assumes that you want to shift the character from a top-center baseline to a bottom-left baseline, and gives you offsets which do that. We don't want to do that so we ignore the offsets. I'm told there is a way of configuring HB's idea of the baseline, and we should use that and take out this condition. */ if (direction != HB_DIRECTION_TTB) { if (glyph_pos[j].x_offset) { lua_pushstring(L, "x_offset"); lua_pushnumber(L, glyph_pos[j].x_offset * point_size / upem); lua_settable(L, -3); } if (glyph_pos[j].y_offset) { lua_pushstring(L, "y_offset"); lua_pushnumber(L, glyph_pos[j].y_offset * point_size / upem); lua_settable(L, -3); } } lua_pushstring(L, "codepoint"); lua_pushinteger(L, glyph_info[j].codepoint); lua_settable(L, -3); lua_pushstring(L, "index"); lua_pushinteger(L, glyph_info[j].cluster); lua_settable(L, -3); double height = extents.y_bearing * point_size / upem; double tHeight = extents.height * point_size / upem; double width = glyph_pos[j].x_advance * point_size / upem; /* The PDF model expects us to make positioning adjustments after a glyph is painted. For this we need to know the natural glyph advance. libtexpdf will use this to compute the adjustment. */ double glyphAdvance = hb_font_get_glyph_h_advance(hbFont, glyph_info[j].codepoint) * point_size / upem; if (direction == HB_DIRECTION_TTB) { height = -glyph_pos[j].y_advance * point_size / upem; tHeight = -height; /* Set depth to 0 - depth has no meaning for TTB */ width = glyphAdvance; glyphAdvance = height; } lua_pushstring(L, "glyphAdvance"); lua_pushnumber(L, glyphAdvance); lua_settable(L, -3); lua_pushstring(L, "width"); lua_pushnumber(L, width); lua_settable(L, -3); lua_pushstring(L, "height"); lua_pushnumber(L, height); lua_settable(L, -3); lua_pushstring(L, "depth"); lua_pushnumber(L, -tHeight - height); lua_settable(L, -3); } /* Cleanup */ hb_buffer_destroy(buf); hb_font_destroy(hbFont); hb_shape_plan_destroy(shape_plan); free(features); return glyph_count; }
int layoutChars(XeTeXLayoutEngine engine, uint16_t chars[], int32_t offset, int32_t count, int32_t max, bool rightToLeft) { bool res; hb_script_t script = HB_SCRIPT_INVALID; hb_direction_t direction = HB_DIRECTION_LTR; hb_segment_properties_t segment_props; hb_shape_plan_t *shape_plan; hb_font_t* hbFont = engine->font->getHbFont(); hb_face_t* hbFace = hb_font_get_face(hbFont); if (engine->font->getLayoutDirVertical()) direction = HB_DIRECTION_TTB; else if (rightToLeft) direction = HB_DIRECTION_RTL; script = hb_ot_tag_to_script (engine->script); if (hbUnicodeFuncs == NULL) hbUnicodeFuncs = _get_unicode_funcs(); hb_buffer_reset(engine->hbBuffer); hb_buffer_set_unicode_funcs(engine->hbBuffer, hbUnicodeFuncs); hb_buffer_add_utf16(engine->hbBuffer, chars, max, offset, count); hb_buffer_set_direction(engine->hbBuffer, direction); hb_buffer_set_script(engine->hbBuffer, script); hb_buffer_set_language(engine->hbBuffer, engine->language); hb_buffer_guess_segment_properties(engine->hbBuffer); hb_buffer_get_segment_properties(engine->hbBuffer, &segment_props); if (engine->ShaperList == NULL) { // HarfBuzz gives graphite2 shaper a priority, so that for hybrid // Graphite/OpenType fonts, Graphite will be used. However, pre-0.9999 // XeTeX preferred OpenType over Graphite, so we are doing the same // here for sake of backward compatibility. engine->ShaperList = (char**) xcalloc(4, sizeof(char*)); engine->ShaperList[0] = (char*) "ot"; engine->ShaperList[1] = (char*) "graphite2"; engine->ShaperList[2] = (char*) "fallback"; engine->ShaperList[3] = NULL; } shape_plan = hb_shape_plan_create_cached(hbFace, &segment_props, engine->features, engine->nFeatures, engine->ShaperList); res = hb_shape_plan_execute(shape_plan, hbFont, engine->hbBuffer, engine->features, engine->nFeatures); if (res) { engine->shaper = strdup(hb_shape_plan_get_shaper(shape_plan)); hb_buffer_set_content_type(engine->hbBuffer, HB_BUFFER_CONTENT_TYPE_GLYPHS); } else { // all selected shapers failed, retrying with default // we don't use _cached here as the cached plain will always fail. hb_shape_plan_destroy(shape_plan); shape_plan = hb_shape_plan_create(hbFace, &segment_props, engine->features, engine->nFeatures, NULL); res = hb_shape_plan_execute(shape_plan, hbFont, engine->hbBuffer, engine->features, engine->nFeatures); if (res) { engine->shaper = strdup(hb_shape_plan_get_shaper(shape_plan)); hb_buffer_set_content_type(engine->hbBuffer, HB_BUFFER_CONTENT_TYPE_GLYPHS); } else { fprintf(stderr, "\nERROR: all shapers failed\n"); exit(3); } } hb_shape_plan_destroy(shape_plan); int glyphCount = hb_buffer_get_length(engine->hbBuffer); #ifdef DEBUG char buf[1024]; unsigned int consumed; printf ("shaper: %s\n", engine->shaper); hb_buffer_serialize_flags_t flags = HB_BUFFER_SERIALIZE_FLAGS_DEFAULT; hb_buffer_serialize_format_t format = HB_BUFFER_SERIALIZE_FORMAT_JSON; hb_buffer_serialize_glyphs (engine->hbBuffer, 0, glyphCount, buf, sizeof(buf), &consumed, hbFont, format, flags); if (consumed) printf ("buffer glyphs: %s\n", buf); #endif return glyphCount; }