< prev index next >
src/java.desktop/share/native/libfontmanager/harfbuzz/hb-ft.cc
Print this page
@@ -25,67 +25,82 @@
*
* Red Hat Author(s): Behdad Esfahbod
* Google Author(s): Behdad Esfahbod
*/
-#include "hb-private.hh"
-#include "hb-debug.hh"
+#include "hb.hh"
#include "hb-ft.h"
-#include "hb-font-private.hh"
+#include "hb-font.hh"
+#include "hb-machinery.hh"
+#include "hb-cache.hh"
#include FT_ADVANCES_H
#include FT_MULTIPLE_MASTERS_H
#include FT_TRUETYPE_TABLES_H
+/**
+ * SECTION:hb-ft
+ * @title: hb-ft
+ * @short_description: FreeType integration
+ * @include: hb-ft.h
+ *
+ * Functions for using HarfBuzz with the FreeType library to provide face and
+ * font data.
+ **/
+
+
/* TODO:
*
* In general, this file does a fine job of what it's supposed to do.
* There are, however, things that need more work:
*
- * - I remember seeing FT_Get_Advance() without the NO_HINTING flag to be buggy.
- * Have not investigated.
- *
* - FreeType works in 26.6 mode. Clients can decide to use that mode, and everything
* would work fine. However, we also abuse this API for performing in font-space,
* but don't pass the correct flags to FreeType. We just abuse the no-hinting mode
* for that, such that no rounding etc happens. As such, we don't set ppem, and
* pass NO_HINTING as load_flags. Would be much better to use NO_SCALE, and scale
- * ourselves, like we do in uniscribe, etc.
+ * ourselves.
*
* - We don't handle / allow for emboldening / obliqueing.
*
* - In the future, we should add constructors to create fonts in font space?
- *
- * - FT_Load_Glyph() is extremely costly. Do something about it?
*/
struct hb_ft_font_t
{
+ mutable hb_mutex_t lock;
FT_Face ft_face;
int load_flags;
bool symbol; /* Whether selected cmap is symbol cmap. */
bool unref; /* Whether to destroy ft_face when done. */
+
+ mutable hb_atomic_int_t cached_x_scale;
+ mutable hb_advance_cache_t advance_cache;
};
static hb_ft_font_t *
_hb_ft_font_create (FT_Face ft_face, bool symbol, bool unref)
{
hb_ft_font_t *ft_font = (hb_ft_font_t *) calloc (1, sizeof (hb_ft_font_t));
if (unlikely (!ft_font))
return nullptr;
+ ft_font->lock.init ();
ft_font->ft_face = ft_face;
ft_font->symbol = symbol;
ft_font->unref = unref;
ft_font->load_flags = FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING;
+ ft_font->cached_x_scale.set (0);
+ ft_font->advance_cache.init ();
+
return ft_font;
}
static void
_hb_ft_face_destroy (void *data)
@@ -96,13 +111,17 @@
static void
_hb_ft_font_destroy (void *data)
{
hb_ft_font_t *ft_font = (hb_ft_font_t *) data;
+ ft_font->advance_cache.fini ();
+
if (ft_font->unref)
_hb_ft_face_destroy (ft_font->ft_face);
+ ft_font->lock.fini ();
+
free (ft_font);
}
/**
* hb_ft_font_set_load_flags:
@@ -114,11 +133,11 @@
* Since: 1.0.5
**/
void
hb_ft_font_set_load_flags (hb_font_t *font, int load_flags)
{
- if (font->immutable)
+ if (hb_object_is_immutable (font))
return;
if (font->destroy != (hb_destroy_func_t) _hb_ft_font_destroy)
return;
@@ -166,10 +185,11 @@
hb_codepoint_t unicode,
hb_codepoint_t *glyph,
void *user_data HB_UNUSED)
{
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+ hb_lock_t lock (ft_font->lock);
unsigned int g = FT_Get_Char_Index (ft_font->ft_face, unicode);
if (unlikely (!g))
{
if (unlikely (ft_font->symbol) && unicode <= 0x00FFu)
@@ -189,53 +209,104 @@
*glyph = g;
return true;
}
+static unsigned int
+hb_ft_get_nominal_glyphs (hb_font_t *font HB_UNUSED,
+ void *font_data,
+ unsigned int count,
+ const hb_codepoint_t *first_unicode,
+ unsigned int unicode_stride,
+ hb_codepoint_t *first_glyph,
+ unsigned int glyph_stride,
+ void *user_data HB_UNUSED)
+{
+ const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+ hb_lock_t lock (ft_font->lock);
+ unsigned int done;
+ for (done = 0;
+ done < count && (*first_glyph = FT_Get_Char_Index (ft_font->ft_face, *first_unicode));
+ done++)
+ {
+ first_unicode = &StructAtOffsetUnaligned<hb_codepoint_t> (first_unicode, unicode_stride);
+ first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
+ }
+ /* We don't need to do ft_font->symbol dance here, since HB calls the singular
+ * nominal_glyph() for what we don't handle here. */
+ return done;
+}
+
+
static hb_bool_t
hb_ft_get_variation_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)
{
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+ hb_lock_t lock (ft_font->lock);
unsigned int g = FT_Face_GetCharVariantIndex (ft_font->ft_face, unicode, variation_selector);
if (unlikely (!g))
return false;
*glyph = g;
return true;
}
-static hb_position_t
-hb_ft_get_glyph_h_advance (hb_font_t *font,
- void *font_data,
- hb_codepoint_t glyph,
+static void
+hb_ft_get_glyph_h_advances (hb_font_t* font, void* font_data,
+ unsigned count,
+ const hb_codepoint_t *first_glyph,
+ unsigned glyph_stride,
+ hb_position_t *first_advance,
+ unsigned advance_stride,
void *user_data HB_UNUSED)
{
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
- FT_Fixed v;
+ hb_lock_t lock (ft_font->lock);
+ FT_Face ft_face = ft_font->ft_face;
+ int load_flags = ft_font->load_flags;
+ int mult = font->x_scale < 0 ? -1 : +1;
- if (unlikely (FT_Get_Advance (ft_font->ft_face, glyph, ft_font->load_flags, &v)))
- return 0;
+ if (font->x_scale != ft_font->cached_x_scale.get ())
+ {
+ ft_font->advance_cache.clear ();
+ ft_font->cached_x_scale.set (font->x_scale);
+ }
- if (font->x_scale < 0)
- v = -v;
+ for (unsigned int i = 0; i < count; i++)
+ {
+ FT_Fixed v = 0;
+ hb_codepoint_t glyph = *first_glyph;
+
+ unsigned int cv;
+ if (ft_font->advance_cache.get (glyph, &cv))
+ v = cv;
+ else
+ {
+ FT_Get_Advance (ft_face, glyph, load_flags, &v);
+ ft_font->advance_cache.set (glyph, v);
+ }
- return (v + (1<<9)) >> 10;
+ *first_advance = (v * mult + (1<<9)) >> 10;
+ first_glyph = &StructAtOffsetUnaligned<hb_codepoint_t> (first_glyph, glyph_stride);
+ first_advance = &StructAtOffsetUnaligned<hb_position_t> (first_advance, advance_stride);
+ }
}
static hb_position_t
hb_ft_get_glyph_v_advance (hb_font_t *font,
void *font_data,
hb_codepoint_t glyph,
void *user_data HB_UNUSED)
{
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+ hb_lock_t lock (ft_font->lock);
FT_Fixed v;
if (unlikely (FT_Get_Advance (ft_font->ft_face, glyph, ft_font->load_flags | FT_LOAD_VERTICAL_LAYOUT, &v)))
return 0;
@@ -254,10 +325,11 @@
hb_position_t *x,
hb_position_t *y,
void *user_data HB_UNUSED)
{
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+ hb_lock_t lock (ft_font->lock);
FT_Face ft_face = ft_font->ft_face;
if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags)))
return false;
@@ -272,35 +344,19 @@
*y = -*y;
return true;
}
-static hb_position_t
-hb_ft_get_glyph_h_kerning (hb_font_t *font,
- void *font_data,
- hb_codepoint_t left_glyph,
- hb_codepoint_t right_glyph,
- void *user_data HB_UNUSED)
-{
- const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
- FT_Vector kerningv;
-
- FT_Kerning_Mode mode = font->x_ppem ? FT_KERNING_DEFAULT : FT_KERNING_UNFITTED;
- if (FT_Get_Kerning (ft_font->ft_face, left_glyph, right_glyph, mode, &kerningv))
- return 0;
-
- return kerningv.x;
-}
-
static hb_bool_t
hb_ft_get_glyph_extents (hb_font_t *font,
void *font_data,
hb_codepoint_t glyph,
hb_glyph_extents_t *extents,
void *user_data HB_UNUSED)
{
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+ hb_lock_t lock (ft_font->lock);
FT_Face ft_face = ft_font->ft_face;
if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags)))
return false;
@@ -329,10 +385,11 @@
hb_position_t *x,
hb_position_t *y,
void *user_data HB_UNUSED)
{
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+ hb_lock_t lock (ft_font->lock);
FT_Face ft_face = ft_font->ft_face;
if (unlikely (FT_Load_Glyph (ft_face, glyph, ft_font->load_flags)))
return false;
@@ -354,12 +411,14 @@
hb_codepoint_t glyph,
char *name, unsigned int size,
void *user_data HB_UNUSED)
{
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+ hb_lock_t lock (ft_font->lock);
+ FT_Face ft_face = ft_font->ft_face;
- hb_bool_t ret = !FT_Get_Glyph_Name (ft_font->ft_face, glyph, name, size);
+ hb_bool_t ret = !FT_Get_Glyph_Name (ft_face, glyph, name, size);
if (ret && (size && !*name))
ret = false;
return ret;
}
@@ -370,10 +429,11 @@
const char *name, int len, /* -1 means nul-terminated */
hb_codepoint_t *glyph,
void *user_data HB_UNUSED)
{
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+ hb_lock_t lock (ft_font->lock);
FT_Face ft_face = ft_font->ft_face;
if (len < 0)
*glyph = FT_Get_Name_Index (ft_face, (FT_String *) name);
else {
@@ -402,79 +462,79 @@
void *font_data,
hb_font_extents_t *metrics,
void *user_data HB_UNUSED)
{
const hb_ft_font_t *ft_font = (const hb_ft_font_t *) font_data;
+ hb_lock_t lock (ft_font->lock);
FT_Face ft_face = ft_font->ft_face;
- metrics->ascender = ft_face->size->metrics.ascender;
- metrics->descender = ft_face->size->metrics.descender;
- metrics->line_gap = ft_face->size->metrics.height - (ft_face->size->metrics.ascender - ft_face->size->metrics.descender);
+ metrics->ascender = FT_MulFix(ft_face->ascender, ft_face->size->metrics.y_scale);
+ metrics->descender = FT_MulFix(ft_face->descender, ft_face->size->metrics.y_scale);
+ metrics->line_gap = FT_MulFix( ft_face->height, ft_face->size->metrics.y_scale ) - (metrics->ascender - metrics->descender);
if (font->y_scale < 0)
{
metrics->ascender = -metrics->ascender;
metrics->descender = -metrics->descender;
metrics->line_gap = -metrics->line_gap;
}
return true;
}
-static hb_font_funcs_t *static_ft_funcs = nullptr;
-
-#ifdef HB_USE_ATEXIT
-static
-void free_static_ft_funcs (void)
-{
-retry:
- hb_font_funcs_t *ft_funcs = (hb_font_funcs_t *) hb_atomic_ptr_get (&static_ft_funcs);
- if (!hb_atomic_ptr_cmpexch (&static_ft_funcs, ft_funcs, nullptr))
- goto retry;
-
- hb_font_funcs_destroy (ft_funcs);
-}
+#if HB_USE_ATEXIT
+static void free_static_ft_funcs ();
#endif
-static void
-_hb_ft_font_set_funcs (hb_font_t *font, FT_Face ft_face, bool unref)
+static struct hb_ft_font_funcs_lazy_loader_t : hb_font_funcs_lazy_loader_t<hb_ft_font_funcs_lazy_loader_t>
{
-retry:
- hb_font_funcs_t *funcs = (hb_font_funcs_t *) hb_atomic_ptr_get (&static_ft_funcs);
-
- if (unlikely (!funcs))
+ static hb_font_funcs_t *create ()
{
- funcs = hb_font_funcs_create ();
+ hb_font_funcs_t *funcs = hb_font_funcs_create ();
hb_font_funcs_set_font_h_extents_func (funcs, hb_ft_get_font_h_extents, nullptr, nullptr);
//hb_font_funcs_set_font_v_extents_func (funcs, hb_ft_get_font_v_extents, nullptr, nullptr);
hb_font_funcs_set_nominal_glyph_func (funcs, hb_ft_get_nominal_glyph, nullptr, nullptr);
+ hb_font_funcs_set_nominal_glyphs_func (funcs, hb_ft_get_nominal_glyphs, nullptr, nullptr);
hb_font_funcs_set_variation_glyph_func (funcs, hb_ft_get_variation_glyph, nullptr, nullptr);
- hb_font_funcs_set_glyph_h_advance_func (funcs, hb_ft_get_glyph_h_advance, nullptr, nullptr);
+ hb_font_funcs_set_glyph_h_advances_func (funcs, hb_ft_get_glyph_h_advances, nullptr, nullptr);
hb_font_funcs_set_glyph_v_advance_func (funcs, hb_ft_get_glyph_v_advance, nullptr, nullptr);
//hb_font_funcs_set_glyph_h_origin_func (funcs, hb_ft_get_glyph_h_origin, nullptr, nullptr);
hb_font_funcs_set_glyph_v_origin_func (funcs, hb_ft_get_glyph_v_origin, nullptr, nullptr);
- hb_font_funcs_set_glyph_h_kerning_func (funcs, hb_ft_get_glyph_h_kerning, nullptr, nullptr);
- //hb_font_funcs_set_glyph_v_kerning_func (funcs, hb_ft_get_glyph_v_kerning, nullptr, nullptr);
hb_font_funcs_set_glyph_extents_func (funcs, hb_ft_get_glyph_extents, nullptr, nullptr);
hb_font_funcs_set_glyph_contour_point_func (funcs, hb_ft_get_glyph_contour_point, nullptr, nullptr);
hb_font_funcs_set_glyph_name_func (funcs, hb_ft_get_glyph_name, nullptr, nullptr);
hb_font_funcs_set_glyph_from_name_func (funcs, hb_ft_get_glyph_from_name, nullptr, nullptr);
hb_font_funcs_make_immutable (funcs);
- if (!hb_atomic_ptr_cmpexch (&static_ft_funcs, nullptr, funcs)) {
- hb_font_funcs_destroy (funcs);
- goto retry;
+#if HB_USE_ATEXIT
+ atexit (free_static_ft_funcs);
+#endif
+
+ return funcs;
}
+} static_ft_funcs;
-#ifdef HB_USE_ATEXIT
- atexit (free_static_ft_funcs); /* First person registers atexit() callback. */
+#if HB_USE_ATEXIT
+static
+void free_static_ft_funcs ()
+{
+ static_ft_funcs.free_instance ();
+}
#endif
- };
+static hb_font_funcs_t *
+_hb_ft_get_font_funcs ()
+{
+ return static_ft_funcs.get_unconst ();
+}
+
+static void
+_hb_ft_font_set_funcs (hb_font_t *font, FT_Face ft_face, bool unref)
+{
bool symbol = ft_face->charmap && ft_face->charmap->encoding == FT_ENCODING_MS_SYMBOL;
hb_font_set_funcs (font,
- funcs,
+ _hb_ft_get_font_funcs (),
_hb_ft_font_create (ft_face, symbol, unref),
_hb_ft_font_destroy);
}
@@ -495,11 +555,12 @@
buffer = (FT_Byte *) malloc (length);
if (!buffer)
return nullptr;
error = FT_Load_Sfnt_Table (ft_face, tag, 0, buffer, &length);
- if (error) {
+ if (error)
+ {
free (buffer);
return nullptr;
}
return hb_blob_create ((const char *) buffer, length,
@@ -681,51 +742,51 @@
{
FT_Reference_Face (ft_face);
return hb_ft_font_create (ft_face, _hb_ft_face_destroy);
}
+#if HB_USE_ATEXIT
+static void free_static_ft_library ();
+#endif
-/* Thread-safe, lock-free, FT_Library */
-
-static FT_Library ft_library;
-
-#ifdef HB_USE_ATEXIT
-static
-void free_ft_library (void)
+static struct hb_ft_library_lazy_loader_t : hb_lazy_loader_t<hb_remove_pointer (FT_Library),
+ hb_ft_library_lazy_loader_t>
{
-retry:
- FT_Library library = (FT_Library) hb_atomic_ptr_get (&ft_library);
- if (!hb_atomic_ptr_cmpexch (&ft_library, library, nullptr))
- goto retry;
+ static FT_Library create ()
+ {
+ FT_Library l;
+ if (FT_Init_FreeType (&l))
+ return nullptr;
- FT_Done_FreeType (library);
-}
+#if HB_USE_ATEXIT
+ atexit (free_static_ft_library);
#endif
-static FT_Library
-get_ft_library (void)
-{
-retry:
- FT_Library library = (FT_Library) hb_atomic_ptr_get (&ft_library);
-
- if (unlikely (!library))
+ return l;
+ }
+ static void destroy (FT_Library l)
+ {
+ FT_Done_FreeType (l);
+ }
+ static FT_Library get_null ()
{
- /* Not found; allocate one. */
- if (FT_Init_FreeType (&library))
return nullptr;
-
- if (!hb_atomic_ptr_cmpexch (&ft_library, nullptr, library)) {
- FT_Done_FreeType (library);
- goto retry;
}
+} static_ft_library;
-#ifdef HB_USE_ATEXIT
- atexit (free_ft_library); /* First person registers atexit() callback. */
+#if HB_USE_ATEXIT
+static
+void free_static_ft_library ()
+{
+ static_ft_library.free_instance ();
+}
#endif
- }
- return library;
+static FT_Library
+get_ft_library ()
+{
+ return static_ft_library.get_unconst ();
}
static void
_release_blob (FT_Face ft_face)
{
< prev index next >