X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=src%2Fhb-ft.cc;h=0589c9eaa9d25dc9278825f43481630a28db0c5d;hb=b08254dad51328fed58b3c0999a1eb7a25f53efc;hp=9535ba1aa576080becc966bac62a5833120f1610;hpb=7033518f756490e9cf00b96387fee6f2f7fae785;p=apps%2Fcore%2Fpreloaded%2Fvideo-player.git diff --git a/src/hb-ft.cc b/src/hb-ft.cc index 9535ba1..0589c9e 100644 --- a/src/hb-ft.cc +++ b/src/hb-ft.cc @@ -31,61 +31,160 @@ #include "hb-font-private.hh" +#include FT_ADVANCES_H #include FT_TRUETYPE_TABLES_H -HB_BEGIN_DECLS + + +#ifndef HB_DEBUG_FT +#define HB_DEBUG_FT (HB_DEBUG+0) +#endif + + +/* TODO: + * + * In general, this file does a fine job of what it's supposed to do. + * There are, however, things that need more work: + * + * - We don't handle any load_flags. That definitely has API implications. :( + * I believe hb_ft_font_create() should take load_flags input. + * In particular, FT_Get_Advance() without the NO_HINTING flag seems to be + * buggy. + * + * - We don't handle / allow for emboldening / obliqueing. + * + * - Rounding, etc? + * + * - In the future, we should add constructors to create fonts in font space. + * + * - I believe transforms are not correctly implemented. FreeType does not + * provide any API to get to the transform/delta set on the face. :( + * + * - Always use FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH? + * + * - FT_Load_Glyph() is exteremely costly. Do something about it? + */ static hb_bool_t -hb_ft_get_contour_point (hb_font_t *font HB_UNUSED, - void *font_data, - hb_codepoint_t glyph, - unsigned int point_index, - hb_position_t *x, - hb_position_t *y, - void *user_data HB_UNUSED) +hb_ft_get_glyph (hb_font_t *font HB_UNUSED, + void *font_data, + hb_codepoint_t unicode, + hb_codepoint_t variation_selector, + hb_codepoint_t *glyph, + void *user_data HB_UNUSED) + { FT_Face ft_face = (FT_Face) font_data; - int load_flags = FT_LOAD_DEFAULT; - /* TODO: load_flags, embolden, etc */ +#ifdef HAVE_FT_FACE_GETCHARVARIANTINDEX + if (unlikely (variation_selector)) { + *glyph = FT_Face_GetCharVariantIndex (ft_face, unicode, variation_selector); + if (*glyph) + return true; + } +#endif - if (unlikely (FT_Load_Glyph (ft_face, glyph, load_flags))) - return FALSE; + *glyph = FT_Get_Char_Index (ft_face, unicode); + return *glyph != 0; +} - if (unlikely (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)) - return FALSE; +static hb_position_t +hb_ft_get_glyph_h_advance (hb_font_t *font HB_UNUSED, + void *font_data, + hb_codepoint_t glyph, + void *user_data HB_UNUSED) +{ + FT_Face ft_face = (FT_Face) font_data; + int load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING; + FT_Fixed v; - if (unlikely (point_index >= (unsigned int) ft_face->glyph->outline.n_points)) - return FALSE; + if (unlikely (FT_Get_Advance (ft_face, glyph, load_flags, &v))) + return 0; - *x = ft_face->glyph->outline.points[point_index].x; - *y = ft_face->glyph->outline.points[point_index].y; + return v >> 10; +} + +static hb_position_t +hb_ft_get_glyph_v_advance (hb_font_t *font HB_UNUSED, + void *font_data, + hb_codepoint_t glyph, + void *user_data HB_UNUSED) +{ + FT_Face ft_face = (FT_Face) font_data; + int load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING | FT_LOAD_VERTICAL_LAYOUT; + FT_Fixed v; + + if (unlikely (FT_Get_Advance (ft_face, glyph, load_flags, &v))) + return 0; - return TRUE; + /* Note: FreeType's vertical metrics grows downward while other FreeType coordinates + * have a Y growing upward. Hence the extra negation. */ + return -v >> 10; } -static void -hb_ft_get_glyph_advance (hb_font_t *font HB_UNUSED, - void *font_data, - hb_codepoint_t glyph, - hb_position_t *x_advance, - hb_position_t *y_advance, - void *user_data HB_UNUSED) +static hb_bool_t +hb_ft_get_glyph_h_origin (hb_font_t *font HB_UNUSED, + void *font_data HB_UNUSED, + hb_codepoint_t glyph HB_UNUSED, + hb_position_t *x HB_UNUSED, + hb_position_t *y HB_UNUSED, + void *user_data HB_UNUSED) +{ + /* We always work in the horizontal coordinates. */ + return true; +} + +static hb_bool_t +hb_ft_get_glyph_v_origin (hb_font_t *font HB_UNUSED, + void *font_data, + hb_codepoint_t glyph, + hb_position_t *x, + hb_position_t *y, + void *user_data HB_UNUSED) { FT_Face ft_face = (FT_Face) font_data; int load_flags = FT_LOAD_DEFAULT; - /* TODO: load_flags, embolden, etc */ + if (unlikely (FT_Load_Glyph (ft_face, glyph, load_flags))) + return false; - if (likely (!FT_Load_Glyph (ft_face, glyph, load_flags))) - { - *x_advance = ft_face->glyph->advance.x; - *y_advance = ft_face->glyph->advance.y; - } + /* Note: FreeType's vertical metrics grows downward while other FreeType coordinates + * have a Y growing upward. Hence the extra negation. */ + *x = ft_face->glyph->metrics.horiBearingX - ft_face->glyph->metrics.vertBearingX; + *y = ft_face->glyph->metrics.horiBearingY - (-ft_face->glyph->metrics.vertBearingY); + + return true; } -static void +static hb_position_t +hb_ft_get_glyph_h_kerning (hb_font_t *font HB_UNUSED, + void *font_data, + hb_codepoint_t left_glyph, + hb_codepoint_t right_glyph, + void *user_data HB_UNUSED) +{ + FT_Face ft_face = (FT_Face) font_data; + FT_Vector kerningv; + + if (FT_Get_Kerning (ft_face, left_glyph, right_glyph, FT_KERNING_DEFAULT, &kerningv)) + return 0; + + return kerningv.x; +} + +static hb_position_t +hb_ft_get_glyph_v_kerning (hb_font_t *font HB_UNUSED, + void *font_data HB_UNUSED, + hb_codepoint_t top_glyph HB_UNUSED, + hb_codepoint_t bottom_glyph HB_UNUSED, + void *user_data HB_UNUSED) +{ + /* FreeType API doesn't support vertical kerning */ + return 0; +} + +static hb_bool_t hb_ft_get_glyph_extents (hb_font_t *font HB_UNUSED, void *font_data, hb_codepoint_t glyph, @@ -95,90 +194,111 @@ hb_ft_get_glyph_extents (hb_font_t *font HB_UNUSED, FT_Face ft_face = (FT_Face) font_data; int load_flags = FT_LOAD_DEFAULT; - /* TODO: load_flags, embolden, etc */ + if (unlikely (FT_Load_Glyph (ft_face, glyph, load_flags))) + return false; - if (likely (!FT_Load_Glyph (ft_face, glyph, load_flags))) - { - /* XXX: A few negations should be in order here, not sure. */ - extents->x_bearing = ft_face->glyph->metrics.horiBearingX; - extents->y_bearing = ft_face->glyph->metrics.horiBearingY; - extents->width = ft_face->glyph->metrics.width; - extents->height = ft_face->glyph->metrics.height; - } + extents->x_bearing = ft_face->glyph->metrics.horiBearingX; + extents->y_bearing = ft_face->glyph->metrics.horiBearingY; + extents->width = ft_face->glyph->metrics.width; + extents->height = ft_face->glyph->metrics.height; + return true; } -static hb_codepoint_t -hb_ft_get_glyph (hb_font_t *font HB_UNUSED, - void *font_data, - hb_codepoint_t unicode, - hb_codepoint_t variation_selector, - void *user_data HB_UNUSED) - +static hb_bool_t +hb_ft_get_glyph_contour_point (hb_font_t *font HB_UNUSED, + void *font_data, + hb_codepoint_t glyph, + unsigned int point_index, + hb_position_t *x, + hb_position_t *y, + void *user_data HB_UNUSED) { FT_Face ft_face = (FT_Face) font_data; + int load_flags = FT_LOAD_DEFAULT; -#ifdef HAVE_FT_FACE_GETCHARVARIANTINDEX - if (unlikely (variation_selector)) { - hb_codepoint_t glyph = FT_Face_GetCharVariantIndex (ft_face, unicode, variation_selector); - if (glyph) - return glyph; - } -#endif + if (unlikely (FT_Load_Glyph (ft_face, glyph, load_flags))) + return false; + + if (unlikely (ft_face->glyph->format != FT_GLYPH_FORMAT_OUTLINE)) + return false; + + if (unlikely (point_index >= (unsigned int) ft_face->glyph->outline.n_points)) + return false; - return FT_Get_Char_Index (ft_face, unicode); + *x = ft_face->glyph->outline.points[point_index].x; + *y = ft_face->glyph->outline.points[point_index].y; + + return true; } -static void -hb_ft_get_kerning (hb_font_t *font HB_UNUSED, - void *font_data, - hb_codepoint_t first_glyph, - hb_codepoint_t second_glyph, - hb_position_t *x_kern, - hb_position_t *y_kern, - void *user_data HB_UNUSED) +static hb_bool_t +hb_ft_get_glyph_name (hb_font_t *font, + void *font_data, + hb_codepoint_t glyph, + char *name, unsigned int size, + void *user_data HB_UNUSED) { FT_Face ft_face = (FT_Face) font_data; - FT_Vector kerning; - /* TODO: Kern type? */ - if (FT_Get_Kerning (ft_face, first_glyph, second_glyph, FT_KERNING_DEFAULT, &kerning)) - return; + hb_bool_t ret = !FT_Get_Glyph_Name (ft_face, glyph, name, size); + if (!ret) + snprintf (name, size, "gid%u", glyph); - *x_kern = kerning.x; - *y_kern = kerning.y; + return ret; } -static hb_font_funcs_t ft_ffuncs = { - HB_OBJECT_HEADER_STATIC, - - TRUE, /* immutable */ +static hb_bool_t +hb_ft_get_glyph_from_name (hb_font_t *font, + void *font_data, + const char *name, int len, /* -1 means nul-terminated */ + hb_codepoint_t *glyph, + void *user_data HB_UNUSED) +{ + FT_Face ft_face = (FT_Face) font_data; - { - hb_ft_get_contour_point, - hb_ft_get_glyph_advance, - hb_ft_get_glyph_extents, - hb_ft_get_glyph, - hb_ft_get_kerning + if (len < 0) + *glyph = FT_Get_Name_Index (ft_face, (FT_String *) name); + else { + /* Make a nul-terminated version. */ + char buf[128]; + len = MIN (len, (int) sizeof (buf) - 1); + strncpy (buf, name, len); + buf[len] = '\0'; + *glyph = FT_Get_Name_Index (ft_face, buf); } -}; -hb_font_funcs_t * -hb_ft_get_font_funcs (void) + return *glyph != 0; +} + + +static hb_font_funcs_t * +_hb_ft_get_font_funcs (void) { - return &ft_ffuncs; + static const hb_font_funcs_t ft_ffuncs = { + HB_OBJECT_HEADER_STATIC, + + true, /* immutable */ + + { +#define HB_FONT_FUNC_IMPLEMENT(name) hb_ft_get_##name, + HB_FONT_FUNCS_IMPLEMENT_CALLBACKS +#undef HB_FONT_FUNC_IMPLEMENT + } + }; + + return const_cast (&ft_ffuncs); } static hb_blob_t * -get_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data) +reference_table (hb_face_t *face HB_UNUSED, hb_tag_t tag, void *user_data) { FT_Face ft_face = (FT_Face) user_data; FT_Byte *buffer; FT_ULong length = 0; FT_Error error; - if (unlikely (tag == HB_TAG_NONE)) - return NULL; + /* Note: FreeType like HarfBuzz uses the NONE tag for fetching the entire blob */ error = FT_Load_Sfnt_Table (ft_face, tag, 0, NULL, &length); if (error) @@ -209,15 +329,21 @@ hb_ft_face_create (FT_Face ft_face, blob = hb_blob_create ((const char *) ft_face->stream->base, (unsigned int) ft_face->stream->size, - /* TODO: Check FT_FACE_FLAG_EXTERNAL_STREAM? */ + /* TODO: We assume that it's mmap()'ed, but FreeType code + * suggests that there are cases we reach here but font is + * not mmapped. For example, when mmap() fails. No idea + * how to deal with it better here. */ HB_MEMORY_MODE_READONLY_MAY_MAKE_WRITABLE, ft_face, destroy); face = hb_face_create (blob, ft_face->face_index); hb_blob_destroy (blob); } else { - face = hb_face_create_for_tables (get_table, ft_face, destroy); + face = hb_face_create_for_tables (reference_table, ft_face, destroy); } + hb_face_set_index (face, ft_face->face_index); + hb_face_set_upem (face, ft_face->units_per_EM); + return face; } @@ -242,6 +368,11 @@ hb_ft_face_create_cached (FT_Face ft_face) return hb_face_reference ((hb_face_t *) ft_face->generic.data); } +static void +_do_nothing (void) +{ +} + hb_font_t * hb_ft_font_create (FT_Face ft_face, @@ -254,8 +385,8 @@ hb_ft_font_create (FT_Face ft_face, font = hb_font_create (face); hb_face_destroy (face); hb_font_set_funcs (font, - hb_ft_get_font_funcs (), - ft_face, NULL); + _hb_ft_get_font_funcs (), + ft_face, (hb_destroy_func_t) _do_nothing); hb_font_set_scale (font, ((uint64_t) ft_face->size->metrics.x_scale * (uint64_t) ft_face->units_per_EM) >> 16, ((uint64_t) ft_face->size->metrics.y_scale * (uint64_t) ft_face->units_per_EM) >> 16); @@ -267,4 +398,91 @@ hb_ft_font_create (FT_Face ft_face, } -HB_END_DECLS +/* Thread-safe, lock-free, FT_Library */ + +static FT_Library ft_library; + +static +void free_ft_library (void) +{ + FT_Done_FreeType (ft_library); +} + +static FT_Library +get_ft_library (void) +{ +retry: + FT_Library library = (FT_Library) hb_atomic_ptr_get (&ft_library); + + if (unlikely (!library)) + { + /* Not found; allocate one. */ + if (FT_Init_FreeType (&library)) + return NULL; + + if (!hb_atomic_ptr_cmpexch (&ft_library, NULL, library)) { + FT_Done_FreeType (library); + goto retry; + } + +#ifdef HAVE_ATEXIT + atexit (free_ft_library); /* First person registers atexit() callback. */ +#endif + } + + return library; +} + +static void +_release_blob (FT_Face ft_face) +{ + hb_blob_destroy ((hb_blob_t *) ft_face->generic.data); +} + +void +hb_ft_font_set_funcs (hb_font_t *font) +{ + hb_blob_t *blob = hb_face_reference_blob (font->face); + unsigned int blob_length; + const char *blob_data = hb_blob_get_data (blob, &blob_length); + if (unlikely (!blob_length)) + DEBUG_MSG (FT, font, "Font face has empty blob"); + + FT_Face ft_face = NULL; + FT_Error err = FT_New_Memory_Face (get_ft_library (), + (const FT_Byte *) blob_data, + blob_length, + hb_face_get_index (font->face), + &ft_face); + + if (unlikely (err)) { + hb_blob_destroy (blob); + DEBUG_MSG (FT, font, "Font face FT_New_Memory_Face() failed"); + return; + } + + FT_Select_Charmap (ft_face, FT_ENCODING_UNICODE); + + FT_Set_Char_Size (ft_face, + font->x_scale, font->y_scale, + font->x_ppem * 72 * 64 / font->x_scale, + font->y_ppem * 72 * 64 / font->y_scale); + + ft_face->generic.data = blob; + ft_face->generic.finalizer = (FT_Generic_Finalizer) _release_blob; + + hb_font_set_funcs (font, + _hb_ft_get_font_funcs (), + ft_face, + (hb_destroy_func_t) FT_Done_Face); +} + +FT_Face +hb_ft_font_get_face (hb_font_t *font) +{ + if (font->destroy == (hb_destroy_func_t) FT_Done_Face || + font->destroy == (hb_destroy_func_t) _do_nothing) + return (FT_Face) font->user_data; + + return NULL; +}