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;
}
Ejemplo n.º 2
0
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;
}