cairo_status_t
_cairo_scaled_font_subsets_map_glyph (cairo_scaled_font_subsets_t	*subsets,
				      cairo_scaled_font_t		*scaled_font,
				      unsigned long			 scaled_font_glyph_index,
				      const char *			 utf8,
				      int				 utf8_len,
                                      cairo_scaled_font_subsets_glyph_t *subset_glyph)
{
    cairo_sub_font_t key, *sub_font;
    cairo_scaled_glyph_t *scaled_glyph;
    cairo_font_face_t *font_face;
    cairo_matrix_t identity;
    cairo_font_options_t font_options;
    cairo_scaled_font_t	*unscaled_font;
    cairo_int_status_t status;
    int max_glyphs;
    cairo_bool_t type1_font;

    /* Lookup glyph in unscaled subsets */
    if (subsets->type != CAIRO_SUBSETS_SCALED) {
        key.is_scaled = FALSE;
        _cairo_sub_font_init_key (&key, scaled_font);
	sub_font = _cairo_hash_table_lookup (subsets->unscaled_sub_fonts,
					     &key.base);
        if (sub_font != NULL) {
            status = _cairo_sub_font_lookup_glyph (sub_font,
						   scaled_font_glyph_index,
						   utf8, utf8_len,
						   subset_glyph);
	    if (status != CAIRO_INT_STATUS_UNSUPPORTED)
                return status;
        }
    }

    /* Lookup glyph in scaled subsets */
    key.is_scaled = TRUE;
    _cairo_sub_font_init_key (&key, scaled_font);
    sub_font = _cairo_hash_table_lookup (subsets->scaled_sub_fonts,
					 &key.base);
    if (sub_font != NULL) {
	status = _cairo_sub_font_lookup_glyph (sub_font,
					       scaled_font_glyph_index,
					       utf8, utf8_len,
					       subset_glyph);
	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
	    return status;
    }

    /* Glyph not found. Determine whether the glyph is outline or
     * bitmap and add to the appropriate subset.
     *
     * glyph_index 0 (the .notdef glyph) is a special case. Some fonts
     * will return CAIRO_INT_STATUS_UNSUPPORTED when doing a
     * _scaled_glyph_lookup(_GLYPH_INFO_PATH). Type1-fallback creates
     * empty glyphs in this case so we can put the glyph in a unscaled
     * subset. */
    if (scaled_font_glyph_index == 0 ||
	_cairo_font_face_is_user (scaled_font->font_face)) {
	status = CAIRO_STATUS_SUCCESS;
    } else {
	_cairo_scaled_font_freeze_cache (scaled_font);
	status = _cairo_scaled_glyph_lookup (scaled_font,
					     scaled_font_glyph_index,
					     CAIRO_SCALED_GLYPH_INFO_PATH,
					     &scaled_glyph);
	_cairo_scaled_font_thaw_cache (scaled_font);
    }
    if (_cairo_int_status_is_error (status))
        return status;

    if (status == CAIRO_INT_STATUS_SUCCESS &&
	subsets->type != CAIRO_SUBSETS_SCALED &&
	! _cairo_font_face_is_user (scaled_font->font_face))
    {
        /* Path available. Add to unscaled subset. */
        key.is_scaled = FALSE;
        _cairo_sub_font_init_key (&key, scaled_font);
	sub_font = _cairo_hash_table_lookup (subsets->unscaled_sub_fonts,
					     &key.base);
        if (sub_font == NULL) {
            font_face = cairo_scaled_font_get_font_face (scaled_font);
            cairo_matrix_init_identity (&identity);
            _cairo_font_options_init_default (&font_options);
            cairo_font_options_set_hint_style (&font_options, CAIRO_HINT_STYLE_NONE);
            cairo_font_options_set_hint_metrics (&font_options, CAIRO_HINT_METRICS_OFF);
            unscaled_font = cairo_scaled_font_create (font_face,
                                                      &identity,
                                                      &identity,
                                                      &font_options);
	    if (unlikely (unscaled_font->status))
		return unscaled_font->status;

            subset_glyph->is_scaled = FALSE;
            type1_font = _cairo_type1_scaled_font_is_type1 (unscaled_font);
            if (subsets->type == CAIRO_SUBSETS_COMPOSITE && !type1_font) {
                max_glyphs = MAX_GLYPHS_PER_COMPOSITE_FONT;
                subset_glyph->is_composite = TRUE;
            } else {
                max_glyphs = MAX_GLYPHS_PER_SIMPLE_FONT;
                subset_glyph->is_composite = FALSE;
            }

            status = _cairo_sub_font_create (subsets,
					     unscaled_font,
					     subsets->num_sub_fonts,
					     max_glyphs,
					     subset_glyph->is_scaled,
					     subset_glyph->is_composite,
					     &sub_font);

            if (unlikely (status)) {
		cairo_scaled_font_destroy (unscaled_font);
                return status;
	    }

            status = _cairo_hash_table_insert (subsets->unscaled_sub_fonts,
                                               &sub_font->base);

            if (unlikely (status)) {
		_cairo_sub_font_destroy (sub_font);
                return status;
	    }
	    if (!subsets->unscaled_sub_fonts_list)
		subsets->unscaled_sub_fonts_list = sub_font;
	    else
		subsets->unscaled_sub_fonts_list_end->next = sub_font;
	    subsets->unscaled_sub_fonts_list_end = sub_font;
	    subsets->num_sub_fonts++;
        }
    } else {
        /* No path available. Add to scaled subset. */
        key.is_scaled = TRUE;
        _cairo_sub_font_init_key (&key, scaled_font);
	sub_font = _cairo_hash_table_lookup (subsets->scaled_sub_fonts,
					     &key.base);
        if (sub_font == NULL) {
            subset_glyph->is_scaled = TRUE;
            subset_glyph->is_composite = FALSE;
            if (subsets->type == CAIRO_SUBSETS_SCALED)
                max_glyphs = INT_MAX;
            else
                max_glyphs = MAX_GLYPHS_PER_SIMPLE_FONT;

            status = _cairo_sub_font_create (subsets,
					     cairo_scaled_font_reference (scaled_font),
					     subsets->num_sub_fonts,
					     max_glyphs,
					     subset_glyph->is_scaled,
					     subset_glyph->is_composite,
					     &sub_font);
            if (unlikely (status)) {
		cairo_scaled_font_destroy (scaled_font);
                return status;
	    }

            status = _cairo_hash_table_insert (subsets->scaled_sub_fonts,
                                               &sub_font->base);
            if (unlikely (status)) {
		_cairo_sub_font_destroy (sub_font);
                return status;
	    }
	    if (!subsets->scaled_sub_fonts_list)
		subsets->scaled_sub_fonts_list = sub_font;
	    else
		subsets->scaled_sub_fonts_list_end->next = sub_font;
	    subsets->scaled_sub_fonts_list_end = sub_font;
	    subsets->num_sub_fonts++;
        }
    }

    return _cairo_sub_font_map_glyph (sub_font,
				      scaled_font_glyph_index,
				      utf8, utf8_len,
				      subset_glyph);
}
static cairo_status_t
_cairo_sub_font_create (cairo_scaled_font_subsets_t	*parent,
			cairo_scaled_font_t		*scaled_font,
			unsigned int			 font_id,
			int				 max_glyphs_per_subset,
                        cairo_bool_t                     is_scaled,
			cairo_bool_t                     is_composite,
			cairo_sub_font_t               **sub_font_out)
{
    cairo_sub_font_t *sub_font;
    cairo_status_t status;
    cairo_scaled_font_subsets_glyph_t subset_glyph;

    sub_font = malloc (sizeof (cairo_sub_font_t));
    if (unlikely (sub_font == NULL))
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);

    sub_font->is_scaled = is_scaled;
    sub_font->is_composite = is_composite;
    sub_font->is_user = _cairo_font_face_is_user (scaled_font->font_face);
    _cairo_sub_font_init_key (sub_font, scaled_font);

    sub_font->parent = parent;
    sub_font->scaled_font = scaled_font;
    sub_font->font_id = font_id;

    sub_font->current_subset = 0;
    sub_font->num_glyphs_in_current_subset = 0;
    sub_font->max_glyphs_per_subset = max_glyphs_per_subset;

    sub_font->sub_font_glyphs = _cairo_hash_table_create (_cairo_sub_font_glyphs_equal);
    if (unlikely (sub_font->sub_font_glyphs == NULL)) {
	free (sub_font);
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    }
    sub_font->next = NULL;

    /* Reserve first glyph in subset for the .notdef glyph except for
     * Type 3 fonts */
    if (! _cairo_font_face_is_user (scaled_font->font_face)) {
	status = _cairo_sub_font_map_glyph (sub_font, 0, NULL, -1, &subset_glyph);
	if (unlikely (status)) {
	    _cairo_hash_table_destroy (sub_font->sub_font_glyphs);
	    free (sub_font);
	    return status;
	}
    }

    *sub_font_out = sub_font;
    return CAIRO_STATUS_SUCCESS;
}
Exemple #3
0
/**
 * cairo_user_font_face_get_unicode_to_glyph_func:
 * @font_face: A user font face
 *
 * Gets the unicode-to-glyph conversion function of a user-font.
 *
 * Return value: The unicode_to_glyph callback of @font_face
 * or %NULL if none set.
 *
 * Since: 1.8
 **/
cairo_user_scaled_font_unicode_to_glyph_func_t
cairo_user_font_face_get_unicode_to_glyph_func (cairo_font_face_t *font_face)
{
    cairo_user_font_face_t *user_font_face = (cairo_user_font_face_t *) font_face;
    if (! _cairo_font_face_is_user (font_face)) {
	if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH))
	    return NULL;
    }
    return user_font_face->scaled_font_methods.unicode_to_glyph;
}
static cairo_status_t
_cairo_sub_font_create (cairo_scaled_font_subsets_t	*parent,
			cairo_scaled_font_t		*scaled_font,
			unsigned int			 font_id,
			int				 max_glyphs_per_subset,
                        cairo_bool_t                     is_scaled,
			cairo_bool_t                     is_composite,
			cairo_sub_font_t               **sub_font_out)
{
    cairo_sub_font_t *sub_font;
    int i;

    sub_font = _cairo_malloc (sizeof (cairo_sub_font_t));
    if (unlikely (sub_font == NULL))
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);

    sub_font->is_scaled = is_scaled;
    sub_font->is_composite = is_composite;
    sub_font->is_user = _cairo_font_face_is_user (scaled_font->font_face);
    sub_font->reserve_notdef = !sub_font->is_user;
    _cairo_sub_font_init_key (sub_font, scaled_font);

    sub_font->parent = parent;
    sub_font->scaled_font = scaled_font;
    sub_font->font_id = font_id;

    sub_font->use_latin_subset = parent->use_latin_subset;

    /* latin subsets of Type 3 and CID CFF fonts are not supported */
    if (sub_font->is_user || sub_font->is_scaled ||
	_cairo_cff_scaled_font_is_cid_cff (scaled_font) )
    {
	sub_font->use_latin_subset = FALSE;
    }

    if (sub_font->use_latin_subset)
	sub_font->current_subset = 1; /* reserve subset 0 for latin glyphs */
    else
	sub_font->current_subset = 0;

    sub_font->num_glyphs_in_current_subset = 0;
    sub_font->num_glyphs_in_latin_subset = 0;
    sub_font->max_glyphs_per_subset = max_glyphs_per_subset;
    for (i = 0; i < 256; i++)
	sub_font->latin_char_map[i] = FALSE;

    sub_font->sub_font_glyphs = _cairo_hash_table_create (NULL);
    if (unlikely (sub_font->sub_font_glyphs == NULL)) {
	free (sub_font);
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    }
    sub_font->next = NULL;
    *sub_font_out = sub_font;
    return CAIRO_STATUS_SUCCESS;
}
Exemple #5
0
/**
 * cairo_user_font_face_set_unicode_to_glyph_func:
 * @font_face: A user font face
 * @unicode_to_glyph_func: The unicode_to_glyph callback, or %NULL
 *
 * Sets the unicode-to-glyph conversion function of a user-font.
 * See #cairo_user_scaled_font_unicode_to_glyph_func_t for details of how the callback
 * works.
 *
 * The font-face should not be immutable or a %CAIRO_STATUS_USER_FONT_IMMUTABLE
 * error will occur.  A user font-face is immutable as soon as a scaled-font
 * is created from it.
 *
 * Since: 1.8
 **/
void
cairo_user_font_face_set_unicode_to_glyph_func (cairo_font_face_t                              *font_face,
						cairo_user_scaled_font_unicode_to_glyph_func_t  unicode_to_glyph_func)
{
    cairo_user_font_face_t *user_font_face = (cairo_user_font_face_t *) font_face;
    if (! _cairo_font_face_is_user (font_face)) {
	if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH))
	    return;
    }
    if (user_font_face->immutable) {
	if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_USER_FONT_IMMUTABLE))
	    return;
    }
    user_font_face->scaled_font_methods.unicode_to_glyph = unicode_to_glyph_func;
}
/**
 * cairo_user_font_face_get_text_to_glyphs_func:
 * @font_face: A user font face
 *
 * Gets the text-to-glyphs conversion function of a user-font.
 *
 * Return value: The text_to_glyphs callback of @font_face
 * or %NULL if none set or an error occurred.
 *
 * Since: 1.8
 **/
cairo_user_scaled_font_text_to_glyphs_func_t
cairo_user_font_face_get_text_to_glyphs_func (cairo_font_face_t *font_face)
{
    cairo_user_font_face_t *user_font_face;

    if (font_face->status)
	return NULL;

    if (! _cairo_font_face_is_user (font_face)) {
	if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH))
	    return NULL;
    }

    user_font_face = (cairo_user_font_face_t *) font_face;
    return user_font_face->scaled_font_methods.text_to_glyphs;
}
/**
 * cairo_user_font_face_set_init_func:
 * @font_face: A user font face
 * @init_func: The init callback, or %NULL
 *
 * Sets the scaled-font initialization function of a user-font.
 * See #cairo_user_scaled_font_init_func_t for details of how the callback
 * works.
 *
 * The font-face should not be immutable or a %CAIRO_STATUS_USER_FONT_IMMUTABLE
 * error will occur.  A user font-face is immutable as soon as a scaled-font
 * is created from it.
 *
 * Since: 1.8
 **/
void
cairo_user_font_face_set_init_func (cairo_font_face_t                  *font_face,
				    cairo_user_scaled_font_init_func_t  init_func)
{
    cairo_user_font_face_t *user_font_face;

    if (font_face->status)
	return;

    if (! _cairo_font_face_is_user (font_face)) {
	if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_FONT_TYPE_MISMATCH))
	    return;
    }

    user_font_face = (cairo_user_font_face_t *) font_face;
    if (user_font_face->immutable) {
	if (_cairo_font_face_set_error (font_face, CAIRO_STATUS_USER_FONT_IMMUTABLE))
	    return;
    }
    user_font_face->scaled_font_methods.init = init_func;
}
static cairo_status_t
_cairo_sub_font_map_glyph (cairo_sub_font_t	*sub_font,
			   unsigned long	 scaled_font_glyph_index,
			   const char		*text_utf8,
			   int			 text_utf8_len,
                           cairo_scaled_font_subsets_glyph_t *subset_glyph)
{
    cairo_sub_font_glyph_t key, *sub_font_glyph;
    cairo_status_t status;

    _cairo_sub_font_glyph_init_key (&key, scaled_font_glyph_index);
    sub_font_glyph = _cairo_hash_table_lookup (sub_font->sub_font_glyphs,
					       &key.base);
    if (sub_font_glyph == NULL) {
	uint32_t font_unicode;
	char *font_utf8;
	int font_utf8_len;
	cairo_bool_t is_latin;
	int latin_character;

	status = _cairo_sub_font_glyph_lookup_unicode (sub_font->scaled_font,
							   scaled_font_glyph_index,
							   &font_unicode,
							   &font_utf8,
							   &font_utf8_len);
	if (unlikely(status))
	    return status;

	/* If the supplied utf8 is a valid single character, use it
	 * instead of the font lookup */
	if (text_utf8 != NULL && text_utf8_len > 0) {
	    uint32_t  *ucs4;
	    int	ucs4_len;

	    status = _cairo_utf8_to_ucs4 (text_utf8, text_utf8_len,
					  &ucs4, &ucs4_len);
	    if (status == CAIRO_STATUS_SUCCESS) {
		if (ucs4_len == 1) {
		    font_unicode = ucs4[0];
		    free (font_utf8);
		    font_utf8 = malloc (text_utf8_len + 1);
		    if (font_utf8 == NULL) {
			free (ucs4);
			return _cairo_error (CAIRO_STATUS_NO_MEMORY);
		    }
		    memcpy (font_utf8, text_utf8, text_utf8_len);
		    font_utf8[text_utf8_len] = 0;
		    font_utf8_len = text_utf8_len;
		}
		free (ucs4);
	    }
	}

	/* If glyph is in the winansi encoding and font is not a user
	 * font, put glyph in the latin subset. If glyph is .notdef
	 * the latin subset is preferred but only if the latin subset
	 * already contains at least one glyph. We don't want to
	 * create a separate subset just for the .notdef glyph.
	 */
	is_latin = FALSE;
	latin_character = -1;
	if (sub_font->use_latin_subset &&
	    (! _cairo_font_face_is_user (sub_font->scaled_font->font_face)))
	{
	    latin_character = _cairo_unicode_to_winansi (font_unicode);
	    if (latin_character > 0 ||
		(latin_character == 0 && sub_font->num_glyphs_in_latin_subset > 0))
	    {
		if (!sub_font->latin_char_map[latin_character]) {
		    sub_font->latin_char_map[latin_character] = TRUE;
		    is_latin = TRUE;
		}
	    }
	}

	status = _cairo_sub_font_add_glyph (sub_font,
					    scaled_font_glyph_index,
					    is_latin,
					    latin_character,
					    font_unicode,
					    font_utf8,
					    font_utf8_len,
					    &sub_font_glyph);
	if (unlikely(status))
	    return status;
    }

    subset_glyph->font_id = sub_font->font_id;
    subset_glyph->subset_id = sub_font_glyph->subset_id;
    if (sub_font_glyph->is_latin)
	subset_glyph->subset_glyph_index = sub_font_glyph->latin_character;
    else
	subset_glyph->subset_glyph_index = sub_font_glyph->subset_glyph_index;

    subset_glyph->is_scaled = sub_font->is_scaled;
    subset_glyph->is_composite = sub_font->is_composite;
    subset_glyph->is_latin = sub_font_glyph->is_latin;
    subset_glyph->x_advance = sub_font_glyph->x_advance;
    subset_glyph->y_advance = sub_font_glyph->y_advance;
    status = _cairo_sub_font_glyph_map_to_unicode (sub_font_glyph,
						   text_utf8, text_utf8_len,
						   &subset_glyph->utf8_is_mapped);
    subset_glyph->unicode = sub_font_glyph->unicode;

    return status;
}
static cairo_status_t
_cairo_sub_font_add_glyph (cairo_sub_font_t	   *sub_font,
			   unsigned long	    scaled_font_glyph_index,
			   cairo_bool_t		    is_latin,
			   int			    latin_character,
			   uint32_t 		    unicode,
			   char 		   *utf8,
			   int 			    utf8_len,
			   cairo_sub_font_glyph_t **sub_font_glyph_out)
{
    cairo_scaled_glyph_t *scaled_glyph;
    cairo_sub_font_glyph_t *sub_font_glyph;
    int *num_glyphs_in_subset_ptr;
    double x_advance;
    double y_advance;
    cairo_int_status_t status;

    _cairo_scaled_font_freeze_cache (sub_font->scaled_font);
    status = _cairo_scaled_glyph_lookup (sub_font->scaled_font,
					 scaled_font_glyph_index,
					 CAIRO_SCALED_GLYPH_INFO_METRICS,
					 &scaled_glyph);
    assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
    if (unlikely (status)) {
	_cairo_scaled_font_thaw_cache (sub_font->scaled_font);
	return status;
    }

    x_advance = scaled_glyph->metrics.x_advance;
    y_advance = scaled_glyph->metrics.y_advance;
    _cairo_scaled_font_thaw_cache (sub_font->scaled_font);

    if (!is_latin && sub_font->num_glyphs_in_current_subset == sub_font->max_glyphs_per_subset)
    {
	sub_font->current_subset++;
	sub_font->num_glyphs_in_current_subset = 0;
    }

    if (is_latin)
	num_glyphs_in_subset_ptr = &sub_font->num_glyphs_in_latin_subset;
    else
	num_glyphs_in_subset_ptr = &sub_font->num_glyphs_in_current_subset;

    /* Reserve first glyph in subset for the .notdef glyph except for
     * Type 3 fonts */
    if (*num_glyphs_in_subset_ptr == 0 &&
	scaled_font_glyph_index != 0 &&
	! _cairo_font_face_is_user (sub_font->scaled_font->font_face))
    {
	status = _cairo_sub_font_add_glyph (sub_font,
					    0,
					    is_latin,
					    0,
					    0,
					    NULL,
					    -1,
					    &sub_font_glyph);
	if (unlikely (status))
	    return status;
    }

    sub_font_glyph = _cairo_sub_font_glyph_create (scaled_font_glyph_index,
						   is_latin ? 0 : sub_font->current_subset,
						   *num_glyphs_in_subset_ptr,
						   x_advance,
						   y_advance,
						   is_latin ? latin_character : -1,
						   unicode,
						   utf8,
						   utf8_len);

    if (unlikely (sub_font_glyph == NULL))
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);

    status = _cairo_hash_table_insert (sub_font->sub_font_glyphs, &sub_font_glyph->base);
    if (unlikely (status)) {
	_cairo_sub_font_glyph_destroy (sub_font_glyph);
	return status;
    }

    (*num_glyphs_in_subset_ptr)++;
    if (sub_font->is_scaled) {
	if (*num_glyphs_in_subset_ptr > sub_font->parent->max_glyphs_per_scaled_subset_used)
	    sub_font->parent->max_glyphs_per_scaled_subset_used = *num_glyphs_in_subset_ptr;
    } else {
	if (*num_glyphs_in_subset_ptr > sub_font->parent->max_glyphs_per_unscaled_subset_used)
	    sub_font->parent->max_glyphs_per_unscaled_subset_used = *num_glyphs_in_subset_ptr;
    }

    *sub_font_glyph_out = sub_font_glyph;

    return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_sub_font_map_glyph (cairo_sub_font_t	*sub_font,
			   unsigned long	 scaled_font_glyph_index,
			   const char		*utf8,
			   int			 utf8_len,
                           cairo_scaled_font_subsets_glyph_t *subset_glyph)
{
    cairo_sub_font_glyph_t key, *sub_font_glyph;
    cairo_status_t status;

    _cairo_sub_font_glyph_init_key (&key, scaled_font_glyph_index);
    sub_font_glyph = _cairo_hash_table_lookup (sub_font->sub_font_glyphs,
					       &key.base);
    if (sub_font_glyph == NULL) {
	cairo_scaled_glyph_t *scaled_glyph;

	if (sub_font->num_glyphs_in_current_subset == sub_font->max_glyphs_per_subset)
	{
	    cairo_scaled_font_subsets_glyph_t tmp_subset_glyph;

	    sub_font->current_subset++;
	    sub_font->num_glyphs_in_current_subset = 0;

	    /* Reserve first glyph in subset for the .notdef glyph
	     * except for Type 3 fonts */
	    if (! _cairo_font_face_is_user (sub_font->scaled_font->font_face)) {
		status = _cairo_sub_font_map_glyph (sub_font, 0, NULL, -1, &tmp_subset_glyph);
		if (unlikely (status))
		    return status;
	    }
	}

	_cairo_scaled_font_freeze_cache (sub_font->scaled_font);
        status = _cairo_scaled_glyph_lookup (sub_font->scaled_font,
                                             scaled_font_glyph_index,
                                             CAIRO_SCALED_GLYPH_INFO_METRICS,
                                             &scaled_glyph);
	assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
	if (unlikely (status)) {
	    _cairo_scaled_font_thaw_cache (sub_font->scaled_font);
	    return status;
	}

        sub_font_glyph = _cairo_sub_font_glyph_create (scaled_font_glyph_index,
						       sub_font->current_subset,
						       sub_font->num_glyphs_in_current_subset,
                                                       scaled_glyph->metrics.x_advance,
                                                       scaled_glyph->metrics.y_advance);
	_cairo_scaled_font_thaw_cache (sub_font->scaled_font);

	if (unlikely (sub_font_glyph == NULL))
	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);

	status = _cairo_sub_font_glyph_lookup_unicode (sub_font_glyph,
						       sub_font->scaled_font,
						       scaled_font_glyph_index);
	if (unlikely (status)) {
	    _cairo_sub_font_glyph_destroy (sub_font_glyph);
	    return status;
	}

	status = _cairo_hash_table_insert (sub_font->sub_font_glyphs, &sub_font_glyph->base);
	if (unlikely (status)) {
	    _cairo_sub_font_glyph_destroy (sub_font_glyph);
	    return status;
	}

	sub_font->num_glyphs_in_current_subset++;

        if (sub_font->is_scaled) {
            if (sub_font->num_glyphs_in_current_subset > sub_font->parent->max_glyphs_per_scaled_subset_used)
                sub_font->parent->max_glyphs_per_scaled_subset_used = sub_font->num_glyphs_in_current_subset;
        } else {
            if (sub_font->num_glyphs_in_current_subset > sub_font->parent->max_glyphs_per_unscaled_subset_used)
                sub_font->parent->max_glyphs_per_unscaled_subset_used = sub_font->num_glyphs_in_current_subset;
        }
    }

    subset_glyph->font_id = sub_font->font_id;
    subset_glyph->subset_id = sub_font_glyph->subset_id;
    subset_glyph->subset_glyph_index = sub_font_glyph->subset_glyph_index;
    subset_glyph->is_scaled = sub_font->is_scaled;
    subset_glyph->is_composite = sub_font->is_composite;
    subset_glyph->x_advance = sub_font_glyph->x_advance;
    subset_glyph->y_advance = sub_font_glyph->y_advance;
    status = _cairo_sub_font_glyph_map_to_unicode (sub_font_glyph,
						   utf8, utf8_len,
						   &subset_glyph->utf8_is_mapped);
    subset_glyph->unicode = sub_font_glyph->unicode;

    return status;
}
cairo_int_status_t
_cairo_scaled_font_subset_create_glyph_names (cairo_scaled_font_subset_t *subset)
{
    unsigned int i;
    cairo_hash_table_t *names;
    cairo_string_entry_t key, *entry;
    char buf[30];
    char *utf8;
    uint16_t *utf16;
    int utf16_len;
    cairo_status_t status = CAIRO_STATUS_SUCCESS;

    names = _cairo_hash_table_create (_cairo_string_equal);
    if (unlikely (names == NULL))
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);

    subset->glyph_names = calloc (subset->num_glyphs, sizeof (char *));
    if (unlikely (subset->glyph_names == NULL)) {
	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
	goto CLEANUP_HASH;
    }

    i = 0;
    if (! _cairo_font_face_is_user (subset->scaled_font->font_face)) {
	subset->glyph_names[0] = strdup (".notdef");
	if (unlikely (subset->glyph_names[0] == NULL)) {
	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
	    goto CLEANUP_HASH;
	}

	status = create_string_entry (subset->glyph_names[0], &entry);
	if (unlikely (status))
	    goto CLEANUP_HASH;

	status = _cairo_hash_table_insert (names, &entry->base);
	if (unlikely (status)) {
	    free (entry);
	    goto CLEANUP_HASH;
	}
	i++;
    }

    for (; i < subset->num_glyphs; i++) {
	utf8 = subset->utf8[i];
	utf16 = NULL;
	utf16_len = 0;
	if (utf8 && *utf8) {
	    status = _cairo_utf8_to_utf16 (utf8, -1, &utf16, &utf16_len);
	    if (unlikely (status))
		goto CLEANUP_HASH;
	}

	if (utf16_len == 1) {
	    snprintf (buf, sizeof (buf), "uni%04X", (int) utf16[0]);
	    _cairo_string_init_key (&key, buf);
	    entry = _cairo_hash_table_lookup (names, &key.base);
	    if (entry != NULL)
		snprintf (buf, sizeof (buf), "g%d", i);
	} else {
	    snprintf (buf, sizeof (buf), "g%d", i);
	}
	if (utf16)
	    free (utf16);

	subset->glyph_names[i] = strdup (buf);
	if (unlikely (subset->glyph_names[i] == NULL)) {
	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
	    goto CLEANUP_HASH;
	}

	status = create_string_entry (subset->glyph_names[i], &entry);
	if (unlikely (status))
	    goto CLEANUP_HASH;

	status = _cairo_hash_table_insert (names, &entry->base);
	if (unlikely (status)) {
	    free (entry);
	    goto CLEANUP_HASH;
	}
    }

CLEANUP_HASH:
    _cairo_hash_table_foreach (names, _pluck_entry, names);
    _cairo_hash_table_destroy (names);

    if (likely (status == CAIRO_STATUS_SUCCESS))
	return CAIRO_STATUS_SUCCESS;

    if (subset->glyph_names != NULL) {
	for (i = 0; i < subset->num_glyphs; i++) {
	    if (subset->glyph_names[i] != NULL)
		free (subset->glyph_names[i]);
	}

	free (subset->glyph_names);
	subset->glyph_names = NULL;
    }

    return status;
}