Esempio n. 1
1
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_int_status_t
_cairo_sub_font_lookup_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_int_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) {
        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;
    }

    return CAIRO_INT_STATUS_UNSUPPORTED;
}
Esempio n. 3
0
static cairo_bool_t
_cairo_toy_font_face_destroy (void *abstract_face)
{
    cairo_toy_font_face_t *font_face = abstract_face;
    cairo_hash_table_t *hash_table;

    hash_table = _cairo_toy_font_face_hash_table_lock ();
    /* All created objects must have been mapped in the hash table. */
    assert (hash_table != NULL);

    if (! _cairo_reference_count_dec_and_test (&font_face->base.ref_count)) {
	/* somebody recreated the font whilst we waited for the lock */
	_cairo_toy_font_face_hash_table_unlock ();
	return FALSE;
    }

    /* Font faces in SUCCESS status are guaranteed to be in the
     * hashtable. Font faces in an error status are removed from the
     * hashtable if they are found during a lookup, thus they should
     * only be removed if they are in the hashtable. */
    if (likely (font_face->base.status == CAIRO_STATUS_SUCCESS) ||
	_cairo_hash_table_lookup (hash_table, &font_face->base.hash_entry) == font_face)
	_cairo_hash_table_remove (hash_table, &font_face->base.hash_entry);

    _cairo_toy_font_face_hash_table_unlock ();

    _cairo_toy_font_face_fini (font_face);
    return TRUE;
}
Esempio n. 4
0
/**
 * _cairo_cache_lookup:
 * @cache: a cache
 * @key: the key of interest
 * @entry_return: pointer for return value
 *
 * Performs a lookup in @cache looking for an entry which has a key
 * that matches @key, (as determined by the keys_equal() function
 * passed to _cairo_cache_init()).
 *
 * Return value: %TRUE if there is an entry in the cache that matches
 * @key, (which will now be in *entry_return). %FALSE otherwise, (in
 * which case *entry_return will be %NULL).
 **/
void *
_cairo_cache_lookup (cairo_cache_t	  *cache,
		     cairo_cache_entry_t  *key)
{
    return _cairo_hash_table_lookup (cache->hash_table,
				     (cairo_hash_entry_t *) key);
}
static cairo_surface_t *
_similar_surface_create (void		 *closure,
			 cairo_content_t  content,
			 double		  width,
			 double		  height,
			 long		  uid)
{
    struct trace *args = closure;
    cairo_surface_t *surface;
    struct scache skey, *s;

    if (args->observe)
	    return cairo_surface_create_similar (args->surface,
						 content, width, height);

    if (uid == 0 || surface_cache == NULL)
	return args->target->create_similar (args->surface, content, width, height);

    skey.entry.hash = uid;
    s = _cairo_hash_table_lookup (surface_cache, &skey.entry);
    if (s != NULL) {
	if (s->content == content &&
	    s->width   == width   &&
	    s->height  == height)
	{
	    return cairo_surface_reference (s->surface);
	}

	/* The surface has been resized, allow the original entry to expire
	 * as it becomes inactive.
	 */
    }

    surface = args->target->create_similar (args->surface, content, width, height);
    s = malloc (sizeof (struct scache));
    if (s == NULL)
	return surface;

    s->entry.hash = uid;
    s->content = content;
    s->width = width;
    s->height = height;
    s->surface = surface;
    if (_cairo_hash_table_insert (surface_cache, &s->entry)) {
	free (s);
    } else if (cairo_surface_set_user_data
	       (surface,
		(const cairo_user_data_key_t *) &surface_cache,
		s, scache_remove))
    {
	scache_remove (s);
    }

    return surface;
}
Esempio n. 6
0
/**
 * cairo_scaled_font_create:
 * @font_face: a #cairo_font_face_t
 * @font_matrix: font space to user space transformation matrix for the
 *       font. In the simplest case of a N point font, this matrix is
 *       just a scale by N, but it can also be used to shear the font
 *       or stretch it unequally along the two axes. See
 *       cairo_set_font_matrix().
 * @ctm: user to device transformation matrix with which the font will
 *       be used.
 * @options: options to use when getting metrics for the font and
 *           rendering with it.
 * 
 * Creates a #cairo_scaled_font_t object from a font face and matrices that
 * describe the size of the font and the environment in which it will
 * be used.
 * 
 * Return value: a newly created #cairo_scaled_font_t. Destroy with
 *  cairo_scaled_font_destroy()
 **/
cairo_scaled_font_t *
cairo_scaled_font_create (cairo_font_face_t          *font_face,
			  const cairo_matrix_t       *font_matrix,
			  const cairo_matrix_t       *ctm,
			  const cairo_font_options_t *options)
{
    cairo_status_t status;
    cairo_scaled_font_map_t *font_map;
    cairo_scaled_font_t key, *scaled_font = NULL;

    if (font_face->status)
	return (cairo_scaled_font_t *)&_cairo_scaled_font_nil;

    font_map = _cairo_scaled_font_map_lock ();
    if (font_map == NULL)
	goto UNWIND;
    
    _cairo_scaled_font_init_key (&key, font_face,
				 font_matrix, ctm, options);

    /* Return existing scaled_font if it exists in the hash table. */
    if (_cairo_hash_table_lookup (font_map->hash_table, &key.hash_entry,
				  (cairo_hash_entry_t**) &scaled_font))
    {
	_cairo_scaled_font_map_unlock ();
	return cairo_scaled_font_reference (scaled_font);
    }

    /* Otherwise create it and insert it into the hash table. */
    status = font_face->backend->scaled_font_create (font_face, font_matrix,
						     ctm, options, &scaled_font);
    if (status)
	goto UNWIND_FONT_MAP_LOCK;

    status = _cairo_hash_table_insert (font_map->hash_table,
				       &scaled_font->hash_entry);
    if (status)
	goto UNWIND_SCALED_FONT_CREATE;

    _cairo_scaled_font_map_unlock ();

    return scaled_font;

UNWIND_SCALED_FONT_CREATE:
    /* We can't call _cairo_scaled_font_destroy here since it expects
     * that the font has already been successfully inserted into the
     * hash table. */
    _cairo_scaled_font_fini (scaled_font);
    free (scaled_font);
UNWIND_FONT_MAP_LOCK:
    _cairo_scaled_font_map_unlock ();
UNWIND:
    return NULL;
}
Esempio n. 7
0
/**
 * _cairo_toy_font_face_create:
 * @family: a font family name, encoded in UTF-8
 * @slant: the slant for the font
 * @weight: the weight for the font
 *
 * Creates a font face from a triplet of family, slant, and weight.
 * These font faces are used in implementation of the the #cairo_t "toy"
 * font API.
 *
 * Return value: a newly created #cairo_font_face_t, destroy with
 *  cairo_font_face_destroy()
 **/
cairo_font_face_t *
_cairo_toy_font_face_create (const char          *family,
			     cairo_font_slant_t   slant,
			     cairo_font_weight_t  weight)
{
    cairo_status_t status;
    cairo_toy_font_face_t key, *font_face;
    cairo_hash_table_t *hash_table;

    hash_table = _cairo_toy_font_face_hash_table_lock ();
    if (hash_table == NULL)
	goto UNWIND;

    _cairo_toy_font_face_init_key (&key, family, slant, weight);

    /* Return existing font_face if it exists in the hash table. */
    if (_cairo_hash_table_lookup (hash_table,
				  &key.base.hash_entry,
				  (cairo_hash_entry_t **) &font_face))
    {
	/* We increment the reference count here manually to avoid
	   double-locking. */
	font_face->base.ref_count++;
	_cairo_toy_font_face_hash_table_unlock ();
	return &font_face->base;
    }

    /* Otherwise create it and insert into hash table. */
    font_face = malloc (sizeof (cairo_toy_font_face_t));
    if (font_face == NULL)
	goto UNWIND_HASH_TABLE_LOCK;

    status = _cairo_toy_font_face_init (font_face, family, slant, weight);
    if (status)
	goto UNWIND_FONT_FACE_MALLOC;

    status = _cairo_hash_table_insert (hash_table, &font_face->base.hash_entry);
    if (status)
	goto UNWIND_FONT_FACE_INIT;

    _cairo_toy_font_face_hash_table_unlock ();

    return &font_face->base;

 UNWIND_FONT_FACE_INIT:
 UNWIND_FONT_FACE_MALLOC:
    free (font_face);
 UNWIND_HASH_TABLE_LOCK:
    _cairo_toy_font_face_hash_table_unlock ();
 UNWIND:
    return (cairo_font_face_t*) &_cairo_font_face_nil;
}
static cairo_status_t
_cairo_sub_font_lookup_glyph (cairo_sub_font_t	                *sub_font,
                              unsigned long	                 scaled_font_glyph_index,
                              cairo_scaled_font_subsets_glyph_t *subset_glyph)
{
    cairo_sub_font_glyph_t key, *sub_font_glyph;

    _cairo_sub_font_glyph_init_key (&key, scaled_font_glyph_index);
    if (_cairo_hash_table_lookup (sub_font->sub_font_glyphs, &key.base,
				    (cairo_hash_entry_t **) &sub_font_glyph))
    {
        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;

        return CAIRO_STATUS_SUCCESS;
    }

    return CAIRO_STATUS_NULL_POINTER;
}
static cairo_bool_t
_cairo_sub_font_lookup_glyph (cairo_sub_font_t	                *sub_font,
                              unsigned long	                 scaled_font_glyph_index,
                              cairo_scaled_font_subsets_glyph_t *subset_glyph)
{
    cairo_sub_font_glyph_t key, *sub_font_glyph;

    _cairo_sub_font_glyph_init_key (&key, scaled_font_glyph_index);
    if (_cairo_hash_table_lookup (sub_font->sub_font_glyphs, &key.base,
				    (cairo_hash_entry_t **) &sub_font_glyph))
    {
        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;

        return TRUE;
    }

    return FALSE;
}
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;
}
Esempio n. 11
0
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;
}
Esempio n. 12
0
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 (! subset->is_scaled) {
	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) {
	    int ch = _cairo_unicode_to_winansi (utf16[0]);
	    if (ch > 0 && _cairo_winansi_to_glyphname (ch))
		strncpy (buf, _cairo_winansi_to_glyphname (ch), sizeof (buf));
	    else
		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);
	}
	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++) {
	    free (subset->glyph_names[i]);
	}

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

    return status;
}
cairo_private 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,
                                      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_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);
        if (_cairo_hash_table_lookup (subsets->unscaled_sub_fonts, &key.base,
                                        (cairo_hash_entry_t **) &sub_font))
        {
            status = _cairo_sub_font_lookup_glyph (sub_font,
                                                   scaled_font_glyph_index,
                                                   subset_glyph);
            if (status == CAIRO_STATUS_SUCCESS)
                return CAIRO_STATUS_SUCCESS;
        }
    }

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

    /* Glyph not found. Determine whether the glyph is outline or
     * bitmap and add to the appropriate subset */
    status = _cairo_scaled_glyph_lookup (scaled_font,
                                         scaled_font_glyph_index,
					 CAIRO_SCALED_GLYPH_INFO_PATH,
                                         &scaled_glyph);
    if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
        return status;

    if (status == 0 && subsets->type != CAIRO_SUBSETS_SCALED) {
        /* Path available. Add to unscaled subset. */
        key.is_scaled = FALSE;
        _cairo_sub_font_init_key (&key, scaled_font);
        if (! _cairo_hash_table_lookup (subsets->unscaled_sub_fonts, &key.base,
                                        (cairo_hash_entry_t **) &sub_font))
        {
            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 (unscaled_font->status)
		return unscaled_font->status;

            subset_glyph->is_scaled = FALSE;
            type1_font = FALSE;
#if CAIRO_HAS_FT_FONT
            type1_font = _cairo_type1_scaled_font_is_type1 (unscaled_font);
#endif
            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;
            }

            sub_font = _cairo_sub_font_create (subsets,
                                               unscaled_font,
                                               subsets->num_sub_fonts++,
                                               max_glyphs,
                                               subset_glyph->is_scaled,
                                               subset_glyph->is_composite);
            if (sub_font == NULL) {
		cairo_scaled_font_destroy (unscaled_font);
                return CAIRO_STATUS_NO_MEMORY;
	    }

            status = _cairo_hash_table_insert (subsets->unscaled_sub_fonts,
                                               &sub_font->base);
            if (status) {
		_cairo_sub_font_destroy (sub_font);
                return status;
	    }
        }
    } else {
        /* No path available. Add to scaled subset. */
        key.is_scaled = TRUE;
        _cairo_sub_font_init_key (&key, scaled_font);
        if (! _cairo_hash_table_lookup (subsets->scaled_sub_fonts, &key.base,
                                        (cairo_hash_entry_t **) &sub_font))
        {
            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;

            sub_font = _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);
            if (sub_font == NULL) {
		cairo_scaled_font_destroy (scaled_font);
                return CAIRO_STATUS_NO_MEMORY;
	    }

            status = _cairo_hash_table_insert (subsets->scaled_sub_fonts,
                                               &sub_font->base);
            if (status) {
		_cairo_sub_font_destroy (sub_font);
                return status;
	    }
        }
    }

    return _cairo_sub_font_map_glyph (sub_font,
                                      scaled_font_glyph_index,
                                      subset_glyph);
}
static cairo_status_t
_cairo_sub_font_map_glyph (cairo_sub_font_t	*sub_font,
			   unsigned long	 scaled_font_glyph_index,
                           cairo_scaled_font_subsets_glyph_t *subset_glyph)
{
    cairo_sub_font_glyph_t key, *sub_font_glyph;
    cairo_status_t status;
    cairo_scaled_glyph_t *scaled_glyph;

    _cairo_sub_font_glyph_init_key (&key, scaled_font_glyph_index);
    if (! _cairo_hash_table_lookup (sub_font->sub_font_glyphs, &key.base,
				    (cairo_hash_entry_t **) &sub_font_glyph))
    {
	if (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 (sub_font->parent->type != CAIRO_SUBSETS_SCALED) {
                /* Reserve first glyph in subset for the .notdef glyph */
                sub_font->num_glyphs_in_current_subset++;
            }
	}

        status = _cairo_scaled_glyph_lookup (sub_font->scaled_font,
                                             scaled_font_glyph_index,
                                             CAIRO_SCALED_GLYPH_INFO_METRICS,
                                             &scaled_glyph);
	if (status)
	    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);
	if (sub_font_glyph == NULL)
	    return CAIRO_STATUS_NO_MEMORY;

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

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

    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;

    return CAIRO_STATUS_SUCCESS;
}
Esempio n. 15
0
/**
 * cairo_toy_font_face_create:
 * @family: a font family name, encoded in UTF-8
 * @slant: the slant for the font
 * @weight: the weight for the font
 *
 * Creates a font face from a triplet of family, slant, and weight.
 * These font faces are used in implementation of the the #cairo_t "toy"
 * font API.
 *
 * If @family is the zero-length string "", the platform-specific default
 * family is assumed.  The default family then can be queried using
 * cairo_toy_font_face_get_family().
 *
 * The cairo_select_font_face() function uses this to create font faces.
 * See that function for limitations and other details of toy font faces.
 *
 * Return value: a newly created #cairo_font_face_t. Free with
 *  cairo_font_face_destroy() when you are done using it.
 *
 * Since: 1.8
 **/
cairo_font_face_t *
cairo_toy_font_face_create (const char          *family,
			    cairo_font_slant_t   slant,
			    cairo_font_weight_t  weight)
{
    cairo_status_t status;
    cairo_toy_font_face_t key, *font_face;
    cairo_hash_table_t *hash_table;

    if (family == NULL)
	return (cairo_font_face_t*) &_cairo_font_face_null_pointer;

    /* Make sure we've got valid UTF-8 for the family */
    status = _cairo_utf8_to_ucs4 (family, -1, NULL, NULL);
    if (unlikely (status)) {
	if (status == CAIRO_STATUS_INVALID_STRING)
	    return (cairo_font_face_t*) &_cairo_font_face_invalid_string;

	return (cairo_font_face_t*) &_cairo_font_face_nil;
    }

    switch (slant) {
	case CAIRO_FONT_SLANT_NORMAL:
	case CAIRO_FONT_SLANT_ITALIC:
	case CAIRO_FONT_SLANT_OBLIQUE:
	    break;
	default:
	    return (cairo_font_face_t*) &_cairo_font_face_invalid_slant;
    }

    switch (weight) {
	case CAIRO_FONT_WEIGHT_NORMAL:
	case CAIRO_FONT_WEIGHT_BOLD:
	    break;
	default:
	    return (cairo_font_face_t*) &_cairo_font_face_invalid_weight;
    }

    if (*family == '\0')
	family = CAIRO_FONT_FAMILY_DEFAULT;

    hash_table = _cairo_toy_font_face_hash_table_lock ();
    if (unlikely (hash_table == NULL))
	goto UNWIND;

    _cairo_toy_font_face_init_key (&key, family, slant, weight);

    /* Return existing font_face if it exists in the hash table. */
    font_face = _cairo_hash_table_lookup (hash_table,
					  &key.base.hash_entry);
    if (font_face != NULL) {
	if (font_face->base.status == CAIRO_STATUS_SUCCESS) {
	    cairo_font_face_reference (&font_face->base);
	    _cairo_toy_font_face_hash_table_unlock ();
	    return &font_face->base;
	}

	/* remove the bad font from the hash table */
	_cairo_hash_table_remove (hash_table, &font_face->base.hash_entry);
    }

    /* Otherwise create it and insert into hash table. */
    font_face = _cairo_malloc (sizeof (cairo_toy_font_face_t));
    if (unlikely (font_face == NULL)) {
	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
	goto UNWIND_HASH_TABLE_LOCK;
    }

    status = _cairo_toy_font_face_init (font_face, family, slant, weight);
    if (unlikely (status))
	goto UNWIND_FONT_FACE_MALLOC;

    assert (font_face->base.hash_entry.hash == key.base.hash_entry.hash);
    status = _cairo_hash_table_insert (hash_table, &font_face->base.hash_entry);
    if (unlikely (status))
	goto UNWIND_FONT_FACE_INIT;

    _cairo_toy_font_face_hash_table_unlock ();

    return &font_face->base;

 UNWIND_FONT_FACE_INIT:
    _cairo_toy_font_face_fini (font_face);
 UNWIND_FONT_FACE_MALLOC:
    free (font_face);
 UNWIND_HASH_TABLE_LOCK:
    _cairo_toy_font_face_hash_table_unlock ();
 UNWIND:
    return (cairo_font_face_t*) &_cairo_font_face_nil;
}
Esempio n. 16
0
/**
 * cairo_toy_font_face_create:
 * @family: a font family name, encoded in UTF-8
 * @slant: the slant for the font
 * @weight: the weight for the font
 *
 * Creates a font face from a triplet of family, slant, and weight.
 * These font faces are used in implementation of the the #cairo_t "toy"
 * font API.
 *
 * If @family is the zero-length string "", the platform-specific default
 * family is assumed.  The default family then can be queried using
 * cairo_toy_font_face_get_family().
 *
 * The cairo_select_font_face() function uses this to create font faces.
 * See that function for limitations of toy font faces.
 *
 * Return value: a newly created #cairo_font_face_t. Free with
 *  cairo_font_face_destroy() when you are done using it.
 *
 * Since: 1.8
 **/
cairo_font_face_t *
cairo_toy_font_face_create (const char          *family,
			    cairo_font_slant_t   slant,
			    cairo_font_weight_t  weight)
{
    cairo_status_t status;
    cairo_toy_font_face_t key, *font_face;
    cairo_hash_table_t *hash_table;

    if (family == NULL)
	return (cairo_font_face_t*) &_cairo_font_face_null_pointer;

    /* Make sure we've got valid UTF-8 for the family */
    status = _cairo_utf8_to_ucs4 (family, -1, NULL, NULL);
    if (status == CAIRO_STATUS_INVALID_STRING)
	return (cairo_font_face_t*) &_cairo_font_face_invalid_string;
    else if (status)
	return (cairo_font_face_t*) &_cairo_font_face_nil;

    switch (slant) {
	case CAIRO_FONT_SLANT_NORMAL:
	case CAIRO_FONT_SLANT_ITALIC:
	case CAIRO_FONT_SLANT_OBLIQUE:
	    break;
	default:
	    return (cairo_font_face_t*) &_cairo_font_face_invalid_slant;
    }

    switch (weight) {
	case CAIRO_FONT_WEIGHT_NORMAL:
	case CAIRO_FONT_WEIGHT_BOLD:
	    break;
	default:
	    return (cairo_font_face_t*) &_cairo_font_face_invalid_weight;
    }

    if (*family == '\0')
	family = CAIRO_FONT_FAMILY_DEFAULT;

    hash_table = _cairo_toy_font_face_hash_table_lock ();
    if (hash_table == NULL)
	goto UNWIND;

    _cairo_toy_font_face_init_key (&key, family, slant, weight);

    /* Return existing font_face if it exists in the hash table. */
    if (_cairo_hash_table_lookup (hash_table,
				  &key.base.hash_entry,
				  (cairo_hash_entry_t **) &font_face))
    {
	if (! font_face->base.status)  {
	    /* We increment the reference count here manually to avoid
	       double-locking. */
	    _cairo_reference_count_inc (&font_face->base.ref_count);
	    _cairo_toy_font_face_hash_table_unlock ();
	    return &font_face->base;
	}

	/* remove the bad font from the hash table */
	_cairo_hash_table_remove (hash_table, &key.base.hash_entry);
	font_face->base.hash_entry.hash = 0;
    }

    /* Otherwise create it and insert into hash table. */
    //+EAWebKitChange
    //11/10/2011
    font_face = cairo_malloc (sizeof (cairo_toy_font_face_t));
    //-EAWebKitChange
    if (font_face == NULL) {
	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
	goto UNWIND_HASH_TABLE_LOCK;
    }

    status = _cairo_toy_font_face_init (font_face, family, slant, weight);
    if (status)
	goto UNWIND_FONT_FACE_MALLOC;

    status = _cairo_hash_table_insert (hash_table, &font_face->base.hash_entry);
    if (status)
	goto UNWIND_FONT_FACE_INIT;

    _cairo_toy_font_face_hash_table_unlock ();

    return &font_face->base;

 UNWIND_FONT_FACE_INIT:
    _cairo_toy_font_face_fini (font_face);
 UNWIND_FONT_FACE_MALLOC:
    //+EAWebKitChange
    //11/10/2011
    cairo_free (font_face);
    //-EAWebKitChange
 UNWIND_HASH_TABLE_LOCK:
    _cairo_toy_font_face_hash_table_unlock ();
 UNWIND:
    return (cairo_font_face_t*) &_cairo_font_face_nil;
}
cairo_int_status_t
_cairo_scaled_font_subset_create_glyph_names (cairo_scaled_font_subset_t *subset)
{
    const cairo_scaled_font_backend_t *backend;
    unsigned int i;
    cairo_status_t status;
    cairo_hash_table_t *names;
    cairo_string_entry_t key, *entry;
    char buf[30];

    if (subset->to_unicode == NULL)
	return CAIRO_INT_STATUS_UNSUPPORTED;

    status = _cairo_truetype_create_glyph_to_unicode_map (subset);
    if (status) {
	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
	    return status;

        backend = subset->scaled_font->backend;
        if (backend->map_glyphs_to_unicode == NULL)
            return CAIRO_INT_STATUS_UNSUPPORTED;

        status = backend->map_glyphs_to_unicode (subset->scaled_font, subset);
	if (status)
	    return status;
    }

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

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

    subset->glyph_names[0] = strdup (".notdef");
    if (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 (status)
	goto CLEANUP_HASH;

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

    for (i = 1; i < subset->num_glyphs; i++) {
	if (subset->to_unicode[i] <= 0xffff) {
	    snprintf (buf, sizeof(buf), "uni%04X", (unsigned int)(subset->to_unicode[i]));
	    _cairo_string_init_key (&key, buf);
	    if (_cairo_hash_table_lookup (names, &key.base,
					  (cairo_hash_entry_t **) &entry)) {
		snprintf (buf, sizeof(buf), "g%d", i);
	    }
	} else {
	    snprintf (buf, sizeof(buf), "g%d", i);
	}

	subset->glyph_names[i] = strdup (buf);
	if (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 (status)
	    goto CLEANUP_HASH;

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

CLEANUP_HASH:
    while (1) {
	entry = _cairo_hash_table_random_entry (names, NULL);
	if (entry == NULL)
	    break;

        _cairo_hash_table_remove (names, (cairo_hash_entry_t *) entry);
        free (entry);
    }
    _cairo_hash_table_destroy (names);

    if (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;
}