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_type3_glyph_surface_emit_fallback_image (cairo_type3_glyph_surface_t *surface,
						unsigned long		     glyph_index)
{
    cairo_scaled_glyph_t *scaled_glyph;
    cairo_status_t status;
    cairo_image_surface_t *image;
    cairo_matrix_t mat;
    double x, y;

    status = _cairo_scaled_glyph_lookup (surface->scaled_font,
					 glyph_index,
					 CAIRO_SCALED_GLYPH_INFO_METRICS |
					 CAIRO_SCALED_GLYPH_INFO_SURFACE,
					 &scaled_glyph);
    if (status)
	return status;

    image = scaled_glyph->surface;
    if (image->width == 0 || image->height == 0)
	return CAIRO_STATUS_SUCCESS;

    x = _cairo_fixed_to_double (scaled_glyph->bbox.p1.x);
    y = _cairo_fixed_to_double (scaled_glyph->bbox.p2.y);
    mat.xx = image->width;
    mat.xy = 0;
    mat.yx = 0;
    mat.yy = image->height;
    mat.x0 = x;
    mat.y0 = y;
    cairo_matrix_multiply (&mat, &mat, &surface->scaled_font->scale_inverse);
    mat.y0 *= -1;

    return _cairo_type3_glyph_surface_emit_image (surface, image, &mat);
}
Exemple #3
0
cairo_status_t
_cairo_scaled_font_text_to_glyphs (cairo_scaled_font_t *scaled_font,
				   double		x,
				   double		y,
				   const char          *utf8, 
				   cairo_glyph_t      **glyphs, 
				   int 		       *num_glyphs)
{
    size_t i;
    uint32_t *ucs4 = NULL;
    cairo_status_t status = CAIRO_STATUS_SUCCESS;
    cairo_scaled_glyph_t *scaled_glyph;

    if (scaled_font->backend->text_to_glyphs) {
	status = scaled_font->backend->text_to_glyphs (scaled_font,
						       x, y, utf8,
						       glyphs, num_glyphs);

        if (status != CAIRO_INT_STATUS_UNSUPPORTED)
            return status;
    }

    status = _cairo_utf8_to_ucs4 ((unsigned char*)utf8, -1, &ucs4, num_glyphs);
    if (status)
	return status;

    *glyphs = (cairo_glyph_t *) malloc ((*num_glyphs) * (sizeof (cairo_glyph_t)));

    if (*glyphs == NULL) {
	status = CAIRO_STATUS_NO_MEMORY;
	goto FAIL;
    }

    for (i = 0; i < *num_glyphs; i++) {            
        (*glyphs)[i].index = (*scaled_font->backend->
			      ucs4_to_index) (scaled_font, ucs4[i]);
	(*glyphs)[i].x = x;
	(*glyphs)[i].y = y;
	
	status = _cairo_scaled_glyph_lookup (scaled_font,
					     (*glyphs)[i].index,
					     CAIRO_SCALED_GLYPH_INFO_METRICS,
					     &scaled_glyph);
	if (status) {
	    free (*glyphs);
	    *glyphs = NULL;
	    goto FAIL;
	}
					     
        x += scaled_glyph->metrics.x_advance;
        y += scaled_glyph->metrics.y_advance;
    }

 FAIL:
    free (ucs4);
    
    return status;
}
Exemple #4
0
/*
 * Compute a device-space bounding box for the glyphs.
 */
cairo_status_t
_cairo_scaled_font_glyph_device_extents (cairo_scaled_font_t	*scaled_font,
					 const cairo_glyph_t	*glyphs,
					 int                     num_glyphs,
					 cairo_rectangle_t	*extents)
{
    cairo_status_t status = CAIRO_STATUS_SUCCESS;
    int i;
    int min_x = CAIRO_MAXSHORT, max_x = CAIRO_MINSHORT;
    int	min_y = CAIRO_MAXSHORT, max_y = CAIRO_MINSHORT;

    if (scaled_font->status)
	return scaled_font->status;

    for (i = 0; i < num_glyphs; i++) {
	cairo_scaled_glyph_t	*scaled_glyph;
	int			left, top;
	int			right, bottom;
	int			x, y;
	
	status = _cairo_scaled_glyph_lookup (scaled_font,
					     glyphs[i].index,
					     CAIRO_SCALED_GLYPH_INFO_METRICS,
					     &scaled_glyph);
	if (status) {
	    _cairo_scaled_font_set_error (scaled_font, status);
	    return status;
	}
	
	/* glyph images are snapped to pixel locations */
	x = (int) floor (glyphs[i].x + 0.5);
	y = (int) floor (glyphs[i].y + 0.5);
	
	left   = x + _cairo_fixed_integer_floor(scaled_glyph->bbox.p1.x);
	top    = y + _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.y);
	right  = x + _cairo_fixed_integer_ceil(scaled_glyph->bbox.p2.x);
	bottom = y + _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.y);
	
	if (left < min_x) min_x = left;
	if (right > max_x) max_x = right;
	if (top < min_y) min_y = top;
	if (bottom > max_y) max_y = bottom;
    }
    if (min_x < max_x && min_y < max_y) {
	extents->x = min_x;
	extents->width = max_x - min_x;
	extents->y = min_y;
	extents->height = max_y - min_y;
    } else {
	extents->x = extents->y = 0;
	extents->width = extents->height = 0;
    }
    return CAIRO_STATUS_SUCCESS;
}
cairo_status_t
_cairo_type3_glyph_surface_analyze_glyph (void		     *abstract_surface,
					  unsigned long	      glyph_index)
{
    cairo_type3_glyph_surface_t *surface = abstract_surface;
    cairo_scaled_glyph_t *scaled_glyph;
    cairo_status_t status, status2;
    cairo_output_stream_t *null_stream;

    if (unlikely (surface->base.status))
	return surface->base.status;

    null_stream = _cairo_null_stream_create ();
    if (unlikely (null_stream->status))
	return null_stream->status;

    _cairo_type3_glyph_surface_set_stream (surface, null_stream);

    _cairo_scaled_font_freeze_cache (surface->scaled_font);
    status = _cairo_scaled_glyph_lookup (surface->scaled_font,
					 glyph_index,
					 CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE,
					 &scaled_glyph);

    if (_cairo_status_is_error (status))
	goto cleanup;

    if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
	status = CAIRO_STATUS_SUCCESS;
	goto cleanup;
    }

    status = _cairo_recording_surface_replay (scaled_glyph->recording_surface,
					      &surface->base);
    if (unlikely (status))
	goto cleanup;

    status = _cairo_pdf_operators_flush (&surface->pdf_operators);
    if (status == CAIRO_INT_STATUS_IMAGE_FALLBACK)
	status = CAIRO_STATUS_SUCCESS;

cleanup:
    _cairo_scaled_font_thaw_cache (surface->scaled_font);

    status2 = _cairo_output_stream_destroy (null_stream);
    if (status == CAIRO_STATUS_SUCCESS)
	status = status2;

    return status;
}
Exemple #6
0
cairo_int_status_t
_cairo_gl_composite_glyphs (void			*_dst,
			    cairo_operator_t		 op,
			    cairo_surface_t		*_src,
			    int				 src_x,
			    int				 src_y,
			    int				 dst_x,
			    int				 dst_y,
			    cairo_composite_glyphs_info_t *info)
{
    cairo_gl_surface_t *dst = _dst;
    cairo_bool_t has_component_alpha;
    int i;

    TRACE ((stderr, "%s\n", __FUNCTION__));

    /* If any of the glyphs are component alpha, we have to go through a mask,
     * since only _cairo_gl_surface_composite() currently supports component
     * alpha.
     */
    if (!dst->base.is_clear && ! info->use_mask && op != CAIRO_OPERATOR_OVER) {
	for (i = 0; i < info->num_glyphs; i++) {
	    cairo_scaled_glyph_t *scaled_glyph;

	    if (_cairo_scaled_glyph_lookup (info->font, info->glyphs[i].index,
					    CAIRO_SCALED_GLYPH_INFO_SURFACE,
					    &scaled_glyph) == CAIRO_INT_STATUS_SUCCESS &&
		scaled_glyph->surface->format == CAIRO_FORMAT_ARGB32)
	    {
		info->use_mask = TRUE;
		break;
	    }
	}
    }

    if (info->use_mask) {
	return render_glyphs_via_mask (dst, dst_x, dst_y,
				       op, _src, info);
    } else {
	return render_glyphs (dst, dst_x, dst_y,
			      op, _src, info,
			      &has_component_alpha);
    }
}
cairo_status_t
_cairo_type3_glyph_surface_analyze_glyph (void		     *abstract_surface,
					  unsigned long	      glyph_index)
{
    cairo_type3_glyph_surface_t *surface = abstract_surface;
    cairo_scaled_glyph_t *scaled_glyph;
    cairo_status_t status, status2;
    cairo_output_stream_t *null_stream;

    null_stream = _cairo_null_stream_create ();
    _cairo_type3_glyph_surface_set_stream (surface, null_stream);
    status = _cairo_scaled_glyph_lookup (surface->scaled_font,
					 glyph_index,
					 CAIRO_SCALED_GLYPH_INFO_METRICS |
					 CAIRO_SCALED_GLYPH_INFO_META_SURFACE,
					 &scaled_glyph);
    if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
	goto cleanup;

    if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
	status = CAIRO_STATUS_SUCCESS;
	goto cleanup;
    }

    status = _cairo_meta_surface_replay (scaled_glyph->meta_surface,
					 &surface->base);

    status = _cairo_pdf_operators_flush (&surface->pdf_operators);
    if (status)
	return status;

    if (status == CAIRO_INT_STATUS_IMAGE_FALLBACK)
	status = CAIRO_STATUS_SUCCESS;

cleanup:
    status2 = _cairo_output_stream_destroy (null_stream);
    if (status)
	return status;

    return status2;
}
Exemple #8
0
cairo_status_t
_cairo_scaled_font_glyph_path (cairo_scaled_font_t *scaled_font,
			       cairo_glyph_t	   *glyphs, 
			       int		    num_glyphs,
			       cairo_path_fixed_t  *path)
{
    cairo_status_t status;
    int	i;
    cairo_scaled_glyph_path_closure_t closure;
    
    if (scaled_font->status)
	return scaled_font->status;
    
    closure.path = path;
    for (i = 0; i < num_glyphs; i++) {
	cairo_scaled_glyph_t *scaled_glyph;
	
	status = _cairo_scaled_glyph_lookup (scaled_font,
					     glyphs[i].index,
					     CAIRO_SCALED_GLYPH_INFO_PATH,
					     &scaled_glyph);
	if (status)
	    return status;

	closure.offset.x = _cairo_fixed_from_double (glyphs[i].x);
	closure.offset.y = _cairo_fixed_from_double (glyphs[i].y);
	
	status = _cairo_path_fixed_interpret (scaled_glyph->path,
					      CAIRO_DIRECTION_FORWARD,
					      _scaled_glyph_path_move_to,
					      _scaled_glyph_path_line_to,
					      _scaled_glyph_path_curve_to,
					      _scaled_glyph_path_close_path,
					      &closure);
    }
    
    return CAIRO_STATUS_SUCCESS;
}
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;
}
cairo_status_t
_cairo_type3_glyph_surface_emit_glyph (void		     *abstract_surface,
				       cairo_output_stream_t *stream,
				       unsigned long	      glyph_index,
				       cairo_box_t           *bbox,
				       double                *width)
{
    cairo_type3_glyph_surface_t *surface = abstract_surface;
    cairo_scaled_glyph_t *scaled_glyph;
    cairo_status_t status, status2;
    double x_advance, y_advance;
    cairo_output_stream_t *mem_stream;
    cairo_matrix_t font_matrix_inverse;

    _cairo_type3_glyph_surface_set_stream (surface, stream);
    status = _cairo_scaled_glyph_lookup (surface->scaled_font,
					 glyph_index,
					 CAIRO_SCALED_GLYPH_INFO_METRICS |
					 CAIRO_SCALED_GLYPH_INFO_META_SURFACE,
					 &scaled_glyph);
    if (status && status != CAIRO_INT_STATUS_UNSUPPORTED)
	return status;

    if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
	status = _cairo_scaled_glyph_lookup (surface->scaled_font,
					     glyph_index,
					     CAIRO_SCALED_GLYPH_INFO_METRICS,
					     &scaled_glyph);
	if (status)
	    return status;

	status = CAIRO_INT_STATUS_IMAGE_FALLBACK;
    }

    x_advance = scaled_glyph->metrics.x_advance;
    y_advance = scaled_glyph->metrics.y_advance;
    font_matrix_inverse = surface->scaled_font->font_matrix;
    status2 = cairo_matrix_invert (&font_matrix_inverse);

    /* The invertability of font_matrix is tested in
     * pdf_operators_show_glyphs before any glyphs are mappped to the
     * subset. */
    assert (status2 == CAIRO_STATUS_SUCCESS);

    cairo_matrix_transform_distance (&font_matrix_inverse, &x_advance, &y_advance);
    *width = x_advance;

    *bbox = scaled_glyph->bbox;
    _cairo_matrix_transform_bounding_box_fixed (&surface->scaled_font->scale_inverse,
						bbox, NULL);

    _cairo_output_stream_printf (surface->stream,
				 "%f 0 %f %f %f %f d1\n",
                                 x_advance,
				 _cairo_fixed_to_double (bbox->p1.x),
				 - _cairo_fixed_to_double (bbox->p2.y),
				 _cairo_fixed_to_double (bbox->p2.x),
				 - _cairo_fixed_to_double (bbox->p1.y));

    if (status == CAIRO_STATUS_SUCCESS) {
	mem_stream = _cairo_memory_stream_create ();
	_cairo_type3_glyph_surface_set_stream (surface, mem_stream);

	_cairo_output_stream_printf (surface->stream, "q\n");
	status = _cairo_meta_surface_replay (scaled_glyph->meta_surface,
					 &surface->base);

	status = _cairo_pdf_operators_flush (&surface->pdf_operators);
	if (status)
	    return status;

	_cairo_output_stream_printf (surface->stream, "Q\n");

	_cairo_type3_glyph_surface_set_stream (surface, stream);
	if (status == CAIRO_STATUS_SUCCESS)
	    _cairo_memory_stream_copy (mem_stream, stream);

	status2 = _cairo_output_stream_destroy (mem_stream);
	if (status2)
	    return status2;
    }

    if (status == CAIRO_INT_STATUS_IMAGE_FALLBACK)
	status = _cairo_type3_glyph_surface_emit_fallback_image (surface, glyph_index);

    return status;
}
Exemple #12
0
/**
 * cairo_scaled_font_glyph_extents:
 * @scaled_font: a #cairo_scaled_font_t
 * @glyphs: an array of glyph IDs with X and Y offsets.
 * @num_glyphs: the number of glyphs in the @glyphs array
 * @extents: a #cairo_text_extents_t which to store the retrieved extents.
 *
 * Gets the extents for an array of glyphs. The extents describe a
 * user-space rectangle that encloses the "inked" portion of the
 * glyphs, (as they would be drawn by cairo_show_glyphs() if the cairo
 * graphics state were set to the same font_face, font_matrix, ctm,
 * and font_options as @scaled_font).  Additionally, the x_advance and
 * y_advance values indicate the amount by which the current point
 * would be advanced by cairo_show_glyphs.
 *
 * Note that whitespace glyphs do not contribute to the size of the
 * rectangle (extents.width and extents.height).
 **/
void
cairo_scaled_font_glyph_extents (cairo_scaled_font_t   *scaled_font,
				 cairo_glyph_t         *glyphs, 
				 int                    num_glyphs,
				 cairo_text_extents_t  *extents)
{
    cairo_status_t status = CAIRO_STATUS_SUCCESS;
    int i;
    double min_x = 0.0, min_y = 0.0, max_x = 0.0, max_y = 0.0;
    double x_pos = 0.0, y_pos = 0.0;

    if (scaled_font->status)
	return;

    if (!num_glyphs) {
	extents->x_bearing = 0.0;
	extents->y_bearing = 0.0;
	extents->width = 0.0;
	extents->height = 0.0;
	extents->x_advance = 0.0;
	extents->y_advance = 0.0;
	
	return;
    }

    for (i = 0; i < num_glyphs; i++) {
	cairo_scaled_glyph_t	*scaled_glyph;
	double			left, top, right, bottom;
	
	status = _cairo_scaled_glyph_lookup (scaled_font,
					     glyphs[i].index,
					     CAIRO_SCALED_GLYPH_INFO_METRICS,
					     &scaled_glyph);
	if (status) {
	    _cairo_scaled_font_set_error (scaled_font, status);
	    return;
	}
	
	left = scaled_glyph->metrics.x_bearing + glyphs[i].x;
	right = left + scaled_glyph->metrics.width;
	top = scaled_glyph->metrics.y_bearing + glyphs[i].y;
	bottom = top + scaled_glyph->metrics.height;
	
	if (i == 0) {
	    min_x = left;
	    max_x = right;
	    min_y = top;
	    max_y = bottom;
	} else {
	    if (left < min_x) min_x = left;
	    if (right > max_x) max_x = right;
	    if (top < min_y) min_y = top;
	    if (bottom > max_y) max_y = bottom;
	}
	x_pos = glyphs[i].x + scaled_glyph->metrics.x_advance;
	y_pos = glyphs[i].y + scaled_glyph->metrics.y_advance;
    }

    extents->x_bearing = min_x - glyphs[0].x;
    extents->y_bearing = min_y - glyphs[0].y;
    extents->width = max_x - min_x;
    extents->height = max_y - min_y;
    extents->x_advance = x_pos - glyphs[0].x;
    extents->y_advance = y_pos - glyphs[0].y;
}
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;
}
static cairo_status_t
_render_glyphs (cairo_gl_surface_t	*dst,
	        int dst_x, int dst_y,
	        cairo_operator_t	 op,
		const cairo_pattern_t	*source,
		cairo_glyph_t		*glyphs,
		int			 num_glyphs,
		const cairo_rectangle_int_t *glyph_extents,
		cairo_scaled_font_t	*scaled_font,
		cairo_region_t		*clip_region,
		int			*remaining_glyphs)
{
    cairo_format_t last_format = (cairo_format_t) -1;
    cairo_gl_glyph_cache_t *cache = NULL;
    cairo_gl_context_t *ctx;
    cairo_gl_glyphs_setup_t setup;
    cairo_gl_composite_setup_t composite_setup;
    cairo_status_t status;
    int i = 0;
    GLuint vbo = 0;

    status = _cairo_gl_operand_init (&composite_setup.src, source, dst,
				     glyph_extents->x, glyph_extents->y,
				     dst_x, dst_y,
				     glyph_extents->width,
				     glyph_extents->height);
    if (unlikely (status))
	return status;

    ctx = _cairo_gl_context_acquire (dst->ctx);

    /* Set up the mask to source from the incoming vertex color. */
    glActiveTexture (GL_TEXTURE1);
    glEnable (GL_TEXTURE_2D);
    /* IN: dst.argb = src.argb * mask.aaaa */
    glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE);
    glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_RGB, GL_MODULATE);
    glTexEnvi (GL_TEXTURE_ENV, GL_COMBINE_ALPHA, GL_MODULATE);

    glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_RGB, GL_PREVIOUS);
    glTexEnvi (GL_TEXTURE_ENV, GL_SRC0_ALPHA, GL_PREVIOUS);
    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_RGB, GL_SRC_COLOR);
    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND0_ALPHA, GL_SRC_ALPHA);

    glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_RGB, GL_TEXTURE1);
    glTexEnvi (GL_TEXTURE_ENV, GL_SRC1_ALPHA, GL_TEXTURE1);
    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_RGB, GL_SRC_ALPHA);
    glTexEnvi (GL_TEXTURE_ENV, GL_OPERAND1_ALPHA, GL_SRC_ALPHA);

    _cairo_gl_set_destination (dst);
    _cairo_gl_set_operator (dst, op);
    _cairo_gl_set_src_operand (ctx, &composite_setup);

    _cairo_scaled_font_freeze_cache (scaled_font);
    if (! _cairo_gl_surface_owns_font (dst, scaled_font)) {
	status = CAIRO_INT_STATUS_UNSUPPORTED;
	goto CLEANUP_FONT;
    }

    if (scaled_font->surface_private == NULL) {
	/* XXX couple into list to remove on context destruction */
	scaled_font->surface_private = ctx;
	scaled_font->surface_backend = &_cairo_gl_surface_backend;
    }

    /* Create our VBO so that we can accumulate a bunch of glyph primitives
     * into one giant DrawArrays.
     */
    memset(&setup, 0, sizeof(setup));
    setup.composite = &composite_setup;
    setup.clip = clip_region;
    setup.dst = dst;
    setup.vertex_size = 4;
    if (composite_setup.src.type == OPERAND_TEXTURE)
	setup.vertex_size += 2;
    setup.vbo_size = num_glyphs * 4 * setup.vertex_size;
    if (setup.vbo_size > 4096)
	setup.vbo_size = 4096;

    glGenBuffersARB (1, &vbo);
    glBindBufferARB (GL_ARRAY_BUFFER_ARB, vbo);

    glVertexPointer (2, GL_FLOAT, setup.vertex_size * sizeof (GLfloat),
		     (void *)(uintptr_t)(0));
    glEnableClientState (GL_VERTEX_ARRAY);
    if (composite_setup.src.type == OPERAND_TEXTURE) {
	/* Note that we're packing texcoord 0 after texcoord 1, for
	 * convenience.
	 */
	glClientActiveTexture (GL_TEXTURE0);
	glTexCoordPointer (2, GL_FLOAT, setup.vertex_size * sizeof (GLfloat),
			   (void *)(uintptr_t)(4 * sizeof (GLfloat)));
	glEnableClientState (GL_TEXTURE_COORD_ARRAY);
    }
    glClientActiveTexture (GL_TEXTURE1);
    glTexCoordPointer (2, GL_FLOAT, setup.vertex_size * sizeof (GLfloat),
		       (void *)(uintptr_t)(2 * sizeof (GLfloat)));
    glEnableClientState (GL_TEXTURE_COORD_ARRAY);

    for (i = 0; i < num_glyphs; i++) {
	cairo_scaled_glyph_t *scaled_glyph;
	double x_offset, y_offset;
	double x1, x2, y1, y2;

	status = _cairo_scaled_glyph_lookup (scaled_font,
					     glyphs[i].index,
					     CAIRO_SCALED_GLYPH_INFO_SURFACE,
					     &scaled_glyph);
	if (unlikely (status))
	    goto FINISH;

	if (scaled_glyph->surface->width  == 0 ||
	    scaled_glyph->surface->height == 0)
	{
	    continue;
	}
	if (scaled_glyph->surface->width  > GLYPH_CACHE_MAX_SIZE ||
	    scaled_glyph->surface->height > GLYPH_CACHE_MAX_SIZE)
	{
	    status = CAIRO_INT_STATUS_UNSUPPORTED;
	    goto FINISH;
	}

	if (scaled_glyph->surface->format != last_format) {
	    /* Switching textures, so flush any queued prims. */
	    _cairo_gl_flush_glyphs (ctx, &setup);

	    glActiveTexture (GL_TEXTURE1);
	    cache = cairo_gl_context_get_glyph_cache (ctx,
						      scaled_glyph->surface->format);

	    glBindTexture (GL_TEXTURE_2D, cache->tex);

	    last_format = scaled_glyph->surface->format;
	}

	if (scaled_glyph->surface_private == NULL) {
	    status = _cairo_gl_glyph_cache_add_glyph (cache, scaled_glyph);
	    if (unlikely (_cairo_status_is_error (status)))
		goto FINISH;

	    if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
		/* Cache is full, so flush existing prims and try again. */
		_cairo_gl_flush_glyphs (ctx, &setup);
		_cairo_gl_glyph_cache_unlock (cache);
	    }

	    status = _cairo_gl_glyph_cache_add_glyph (cache, scaled_glyph);
	    if (unlikely (status))
		goto FINISH;
	}

	x_offset = scaled_glyph->surface->base.device_transform.x0;
	y_offset = scaled_glyph->surface->base.device_transform.y0;

	x1 = _cairo_lround (glyphs[i].x - x_offset);
	y1 = _cairo_lround (glyphs[i].y - y_offset);
	x2 = x1 + scaled_glyph->surface->width;
	y2 = y1 + scaled_glyph->surface->height;

	_cairo_gl_emit_glyph_rectangle (ctx, &setup,
					x1, y1, x2, y2,
					_cairo_gl_glyph_cache_lock (cache, scaled_glyph));
    }

    status = CAIRO_STATUS_SUCCESS;
  FINISH:
    _cairo_gl_flush_glyphs (ctx, &setup);
  CLEANUP_FONT:
    _cairo_scaled_font_thaw_cache (scaled_font);

    glDisable (GL_BLEND);
    glDisable (GL_SCISSOR_TEST);

    glDisableClientState (GL_VERTEX_ARRAY);

    glClientActiveTexture (GL_TEXTURE0);
    glDisableClientState (GL_TEXTURE_COORD_ARRAY);
    glActiveTexture (GL_TEXTURE0);
    glDisable (GL_TEXTURE_2D);

    glClientActiveTexture (GL_TEXTURE1);
    glDisableClientState (GL_TEXTURE_COORD_ARRAY);
    glActiveTexture (GL_TEXTURE1);
    glDisable (GL_TEXTURE_2D);

    if (vbo != 0) {
	glBindBufferARB (GL_ARRAY_BUFFER_ARB, 0);
	glDeleteBuffersARB (1, &vbo);
    }

    _cairo_gl_context_release (ctx);

    _cairo_gl_operand_destroy (&composite_setup.src);

    *remaining_glyphs = num_glyphs - i;
    return status;
}
Exemple #15
0
cairo_int_status_t
i965_surface_glyphs (void			*abstract_surface,
		     cairo_operator_t		 op,
		     const cairo_pattern_t	*source,
		     cairo_glyph_t		*g,
		     int			 num_glyphs,
		     cairo_scaled_font_t	*scaled_font,
		     cairo_clip_t		*clip,
		     int *num_remaining)
{
    i965_surface_t *surface = abstract_surface;
    i965_surface_t *mask = NULL;
    i965_device_t *device;
    i965_glyphs_t glyphs;
    cairo_composite_rectangles_t extents;
    cairo_clip_t local_clip;
    cairo_bool_t have_clip = FALSE;
    cairo_bool_t overlap;
    cairo_region_t *clip_region = NULL;
    intel_bo_t *last_bo = NULL;
    cairo_scaled_glyph_t *glyph_cache[64];
    cairo_status_t status;
    int mask_x = 0, mask_y = 0;
    int i = 0;

    *num_remaining = 0;
    status = _cairo_composite_rectangles_init_for_glyphs (&extents,
							  surface->intel.drm.width,
							  surface->intel.drm.height,
							  op, source,
							  scaled_font,
							  g, num_glyphs,
							  clip,
							  &overlap);
    if (unlikely (status))
	return status;

    if (clip != NULL && _cairo_clip_contains_rectangle (clip, &extents.mask))
	clip = NULL;

    if (clip != NULL && extents.is_bounded) {
	clip = _cairo_clip_init_copy (&local_clip, clip);
	status = _cairo_clip_rectangle (clip, &extents.bounded);
	if (unlikely (status))
	    return status;

	have_clip = TRUE;
    }

    if (overlap || ! extents.is_bounded) {
	cairo_format_t format;

	format = CAIRO_FORMAT_A8;
	if (scaled_font->options.antialias == CAIRO_ANTIALIAS_SUBPIXEL)
	    format = CAIRO_FORMAT_ARGB32;

	mask = (i965_surface_t *)
	    i965_surface_create_internal (&i965_device (surface)->intel.base,
					  format,
					  extents.bounded.width,
					  extents.bounded.height,
					  I965_TILING_DEFAULT,
					  TRUE);
	if (unlikely (mask->intel.drm.base.status))
	    return mask->intel.drm.base.status;

	status = _cairo_surface_paint (&mask->intel.drm.base,
				       CAIRO_OPERATOR_CLEAR,
				       &_cairo_pattern_clear.base,
				       NULL);
	if (unlikely (status)) {
	    cairo_surface_destroy (&mask->intel.drm.base);
	    return status;
	}

	i965_shader_init (&glyphs.shader, mask, CAIRO_OPERATOR_ADD);

	status = i965_shader_acquire_pattern (&glyphs.shader, &glyphs.shader.source,
					      &_cairo_pattern_white.base,
					      &extents.bounded);
	if (unlikely (status)) {
	    cairo_surface_destroy (&mask->intel.drm.base);
	    return status;
	}

	mask_x = -extents.bounded.x;
	mask_y = -extents.bounded.y;
    } else {
	i965_shader_init (&glyphs.shader, surface, op);

	status = i965_shader_acquire_pattern (&glyphs.shader, &glyphs.shader.source,
					      source, &extents.bounded);
	if (unlikely (status))
	    return status;

	if (clip != NULL) {
	    status = _cairo_clip_get_region (clip, &clip_region);
	    assert (status == CAIRO_STATUS_SUCCESS || status == CAIRO_INT_STATUS_UNSUPPORTED);

	    if (status == CAIRO_INT_STATUS_UNSUPPORTED)
		i965_shader_set_clip (&glyphs.shader, clip);
	}
    }

    glyphs.head.next = NULL;
    glyphs.head.bo = NULL;
    glyphs.head.count = 0;
    glyphs.tail = &glyphs.head;

    device = i965_device (surface);
    if (mask != NULL || clip_region == NULL) {
	glyphs.get_rectangle = i965_glyphs_emit_rectangle;
    } else {
	glyphs.get_rectangle = i965_glyphs_accumulate_rectangle;
	glyphs.head.bo = intel_bo_create (&device->intel,
					  I965_VERTEX_SIZE, I965_VERTEX_SIZE,
					  FALSE, I915_TILING_NONE, 0);
	if (unlikely (glyphs.head.bo == NULL))
	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);

	glyphs.vbo_base = intel_bo_map (&device->intel, glyphs.head.bo);
    }
    glyphs.vbo_offset = 0;

    status = cairo_device_acquire (&device->intel.base.base);
    if (unlikely (status))
	goto CLEANUP_GLYPHS;

    _cairo_scaled_font_freeze_cache (scaled_font);
    //private = _cairo_scaled_font_get_device (scaled_font, device);
    if (scaled_font->surface_private == NULL) {
	scaled_font->surface_private = device;
	scaled_font->surface_backend = surface->intel.drm.base.backend;
	cairo_list_add (&scaled_font->link, &device->intel.fonts);
    }

    memset (glyph_cache, 0, sizeof (glyph_cache));

    for (i = 0; i < num_glyphs; i++) {
	cairo_scaled_glyph_t *scaled_glyph;
	int x, y, x1, x2, y1, y2;
	int cache_index = g[i].index % ARRAY_LENGTH (glyph_cache);
	intel_glyph_t *glyph;

	scaled_glyph = glyph_cache[cache_index];
	if (scaled_glyph == NULL ||
	    _cairo_scaled_glyph_index (scaled_glyph) != g[i].index)
	{
	    status = _cairo_scaled_glyph_lookup (scaled_font,
						 g[i].index,
						 CAIRO_SCALED_GLYPH_INFO_METRICS,
						 &scaled_glyph);
	    if (unlikely (status))
		goto FINISH;

	    glyph_cache[cache_index] = scaled_glyph;
	}

	if (unlikely (scaled_glyph->metrics.width  == 0 ||
		      scaled_glyph->metrics.height == 0))
	{
	    continue;
	}

	/* XXX glyph images are snapped to pixel locations */
	x = _cairo_lround (g[i].x);
	y = _cairo_lround (g[i].y);

	x1 = x + _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.x);
	y1 = y + _cairo_fixed_integer_floor (scaled_glyph->bbox.p1.y);
	x2 = x + _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.x);
	y2 = y + _cairo_fixed_integer_ceil (scaled_glyph->bbox.p2.y);

	if (x2 < extents.bounded.x ||
	    y2 < extents.bounded.y ||
	    x1 > extents.bounded.x + extents.bounded.width ||
	    y1 > extents.bounded.y + extents.bounded.height)
	{
	    continue;
	}

	if (scaled_glyph->surface_private == NULL) {
	    status = intel_get_glyph (&device->intel, scaled_font, scaled_glyph);
	    if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO)) {
		status = CAIRO_STATUS_SUCCESS;
		continue;
	    }
	    if (unlikely (status))
		goto FINISH;
	}
	glyph = intel_glyph_pin (scaled_glyph->surface_private);

	if (glyph->cache->buffer.bo != last_bo) {
	    intel_buffer_cache_t *cache = glyph->cache;

	    glyphs.shader.mask.type.vertex   = VS_GLYPHS;
	    glyphs.shader.mask.type.fragment = FS_GLYPHS;
	    glyphs.shader.mask.type.pattern  = PATTERN_BASE;

	    glyphs.shader.mask.base.bo = cache->buffer.bo;
	    glyphs.shader.mask.base.format = cache->buffer.format;
	    glyphs.shader.mask.base.width  = cache->buffer.width;
	    glyphs.shader.mask.base.height = cache->buffer.height;
	    glyphs.shader.mask.base.stride = cache->buffer.stride;
	    glyphs.shader.mask.base.filter = i965_filter (CAIRO_FILTER_NEAREST);
	    glyphs.shader.mask.base.extend = i965_extend (CAIRO_EXTEND_NONE);
	    glyphs.shader.mask.base.content = CAIRO_CONTENT_ALPHA; /* XXX */

	    glyphs.shader.committed = FALSE;
	    status = i965_shader_commit (&glyphs.shader, device);
	    if (unlikely (status))
		goto FINISH;

	    last_bo = cache->buffer.bo;
	}

	x2 = x1 + glyph->width;
	y2 = y1 + glyph->height;

	if (mask_x)
	    x1 += mask_x, x2 += mask_x;
	if (mask_y)
	    y1 += mask_y, y2 += mask_y;

	i965_add_glyph_rectangle (&glyphs, x1, y1, x2, y2, glyph);
    }

    if (mask != NULL && clip_region != NULL)
	i965_clipped_vertices (device, &glyphs.head, clip_region);

    status = CAIRO_STATUS_SUCCESS;
  FINISH:
    _cairo_scaled_font_thaw_cache (scaled_font);
    cairo_device_release (surface->intel.drm.base.device);
  CLEANUP_GLYPHS:
    i965_shader_fini (&glyphs.shader);

    if (glyphs.head.bo != NULL) {
	struct i965_vbo *vbo, *next;

	intel_bo_destroy (&device->intel, glyphs.head.bo);
	for (vbo = glyphs.head.next; vbo != NULL; vbo = next) {
	    next = vbo->next;
	    intel_bo_destroy (&device->intel, vbo->bo);
	    free (vbo);
	}
    }

    if (unlikely (status == CAIRO_INT_STATUS_UNSUPPORTED)) {
	cairo_path_fixed_t path;

	_cairo_path_fixed_init (&path);
	status = _cairo_scaled_font_glyph_path (scaled_font,
						g + i, num_glyphs - i,
						&path);
	if (mask_x | mask_y) {
	    _cairo_path_fixed_translate (&path,
					 _cairo_fixed_from_int (mask_x),
					 _cairo_fixed_from_int (mask_y));
	}
	if (likely (status == CAIRO_STATUS_SUCCESS)) {
	    status = surface->intel.drm.base.backend->fill (glyphs.shader.target,
							    glyphs.shader.op,
							    mask != NULL ? &_cairo_pattern_white.base : source,
							    &path,
							    CAIRO_FILL_RULE_WINDING,
							    0,
							    scaled_font->options.antialias,
							    clip);
	}
	_cairo_path_fixed_fini (&path);
    }

    if (mask != NULL) {
	if (likely (status == CAIRO_STATUS_SUCCESS)) {
	    status = i965_surface_mask_internal (surface, op, source, mask,
					         clip, &extents);
	}
	cairo_surface_finish (&mask->intel.drm.base);
	cairo_surface_destroy (&mask->intel.drm.base);
    }

    if (have_clip)
	_cairo_clip_fini (&local_clip);

    return status;
}
static cairo_int_status_t
composite_glyphs (cairo_image_surface_t	*dst,
		  void			 *closure,
		  cairo_operator_t	 op,
		  const cairo_pattern_t	*pattern,
		  int			 dst_x,
		  int			 dst_y,
		  const cairo_rectangle_int_t *extents)
{
    cairo_composite_glyphs_info_t *info = closure;
    pixman_image_t *mask;
    cairo_status_t status;
    int i;

    mask = pixman_image_create_bits (PIXMAN_a8,
				     extents->width, extents->height,
				     NULL, 0);
    if (unlikely (mask == NULL))
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);

    status = CAIRO_STATUS_SUCCESS;
    _cairo_scaled_font_freeze_cache (info->font);
    for (i = 0; i < info->num_glyphs; i++) {
	cairo_image_surface_t *glyph_surface;
	cairo_scaled_glyph_t *scaled_glyph;
	unsigned long glyph_index = info->glyphs[i].index;
	int x, y;

	status = _cairo_scaled_glyph_lookup (info->font, glyph_index,
					     CAIRO_SCALED_GLYPH_INFO_SURFACE,
					     &scaled_glyph);

	if (unlikely (status))
	    break;

	glyph_surface = scaled_glyph->surface;
	if (glyph_surface->width && glyph_surface->height) {
	    /* round glyph locations to the nearest pixel */
	    /* XXX: FRAGILE: We're ignoring device_transform scaling here. A bug? */
	    x = _cairo_lround (info->glyphs[i].x -
			       glyph_surface->base.device_transform.x0);
	    y = _cairo_lround (info->glyphs[i].y -
			       glyph_surface->base.device_transform.y0);

	    pixman_image_composite32 (PIXMAN_OP_ADD,
				      glyph_surface->pixman_image, NULL, mask,
				      0, 0,
                                      0, 0,
                                      x - extents->x, y - extents->y,
				      glyph_surface->width,
				      glyph_surface->height);
	}
    }
    _cairo_scaled_font_thaw_cache (info->font);

    if (status == CAIRO_STATUS_SUCCESS) {
	cairo_rectangle_int_t sample;
	pixman_image_t *src;
	int src_x, src_y;

	_cairo_pattern_sampled_area (pattern, extents, &sample);
	src = _pixman_image_for_pattern (dst, pattern, FALSE,
					 extents, &sample,
					 &src_x, &src_y);
	if (src != NULL) {
	    dst_x = extents->x - dst_x;
	    dst_y = extents->y - dst_y;
	    pixman_image_composite32 (_pixman_operator (op),
				      src, mask, dst->pixman_image,
				      src_x + dst_x,  src_y + dst_y,
				      0, 0,
				      dst_x, dst_y,
				      extents->width, extents->height);
	    pixman_image_unref (src);
	} else
	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
    }
    pixman_image_unref (mask);

    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;
}
Exemple #18
0
cairo_status_t
_cairo_scaled_font_show_glyphs (cairo_scaled_font_t    *scaled_font,
				cairo_operator_t        op,
				cairo_pattern_t        *pattern,
				cairo_surface_t        *surface,
				int                     source_x,
				int                     source_y,
				int			dest_x,
				int			dest_y,
				unsigned int		width,
				unsigned int		height,
				const cairo_glyph_t    *glyphs,
				int                     num_glyphs)
{
    cairo_status_t status;
    cairo_surface_t *mask = NULL;
    int i;

    /* These operators aren't interpreted the same way by the backends;
     * they are implemented in terms of other operators in cairo-gstate.c
     */
    assert (op != CAIRO_OPERATOR_SOURCE && op != CAIRO_OPERATOR_CLEAR);
    
    if (scaled_font->status)
	return scaled_font->status;

    if (scaled_font->backend->show_glyphs != NULL) {
	status = scaled_font->backend->show_glyphs (scaled_font,
						    op, pattern, 
						    surface,
						    source_x, source_y,
						    dest_x, dest_y,
						    width, height,
						    glyphs, num_glyphs);
	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
	    return status;
    }

    /* Font display routine either does not exist or failed. */
    
    status = CAIRO_STATUS_SUCCESS;

    _cairo_cache_freeze (scaled_font->glyphs);

    for (i = 0; i < num_glyphs; i++) {
	int x, y;
	cairo_surface_pattern_t glyph_pattern;
	cairo_image_surface_t *glyph_surface;
	cairo_scaled_glyph_t *scaled_glyph;
	
	status = _cairo_scaled_glyph_lookup (scaled_font,
					     glyphs[i].index,
					     CAIRO_SCALED_GLYPH_INFO_SURFACE,
					     &scaled_glyph);

	if (status)
	    goto CLEANUP_MASK;
	
	glyph_surface = scaled_glyph->surface;

	/* Create the mask using the format from the first glyph */
	if (mask == NULL) {
	    mask = cairo_image_surface_create (glyph_surface->format,
					       width, height);
	    if (mask->status) {
		status = mask->status;
		goto CLEANUP_MASK;
	    }

	    status = _cairo_surface_fill_rectangle (mask,
						    CAIRO_OPERATOR_CLEAR,
						    CAIRO_COLOR_TRANSPARENT,
						    0, 0,
						    width, height);
	    if (status)
		goto CLEANUP_MASK;
	    if (glyph_surface->format == CAIRO_FORMAT_ARGB32)
		pixman_image_set_component_alpha (((cairo_image_surface_t*) mask)->
						  pixman_image, TRUE);

	}
	
	/* round glyph locations to the nearest pixel */
	x = (int) floor (glyphs[i].x + 
			 glyph_surface->base.device_x_offset +
			 0.5);
	y = (int) floor (glyphs[i].y +
			 glyph_surface->base.device_y_offset +
			 0.5);
	
	_cairo_pattern_init_for_surface (&glyph_pattern, &glyph_surface->base);

	status = _cairo_surface_composite (CAIRO_OPERATOR_ADD, 
					   &glyph_pattern.base, 
					   NULL,
					   mask,
					   0, 0,
					   0, 0, 
					   x - dest_x, 
					   y - dest_y, 
					   glyph_surface->width,
					   glyph_surface->height);

	_cairo_pattern_fini (&glyph_pattern.base);
	if (status)
	    break;
    }
    
    if (mask != NULL) {
	cairo_surface_pattern_t mask_pattern;

	_cairo_pattern_init_for_surface (&mask_pattern, mask);
    
	status = _cairo_surface_composite (op, pattern, &mask_pattern.base,
					   surface,
					   source_x, source_y, 
					   0,        0,
					   dest_x,   dest_y,
					   width,    height);
    
	_cairo_pattern_fini (&mask_pattern.base);
    }
	
CLEANUP_MASK:
    _cairo_cache_thaw (scaled_font->glyphs);
    
    if (mask != NULL)
	cairo_surface_destroy (mask);
    return status;
}
Exemple #19
0
static cairo_status_t
render_glyphs (cairo_gl_surface_t *dst,
	       int dst_x, int dst_y,
	       cairo_operator_t op,
	       cairo_surface_t *source,
	       cairo_composite_glyphs_info_t *info,
	       cairo_bool_t *has_component_alpha,
	       cairo_clip_t *clip,
	       cairo_bool_t via_msaa_compositor)
{
    cairo_format_t last_format = CAIRO_FORMAT_INVALID;
    cairo_gl_glyph_cache_t *cache = NULL;
    cairo_gl_context_t *ctx;
    cairo_gl_composite_t setup;
    cairo_int_status_t status;
    int i = 0;
    cairo_bool_t is_argb32;

    TRACE ((stderr, "%s (%d, %d)x(%d, %d)\n", __FUNCTION__,
	    info->extents.x, info->extents.y,
	    info->extents.width, info->extents.height));

    *has_component_alpha = FALSE;

    status = _cairo_gl_context_acquire (dst->base.device, &ctx);
    if (unlikely (status))
	return status;

    /* Traps compositor never has CLEAR operator. */
    is_argb32 =
	info->font->options.antialias == CAIRO_ANTIALIAS_SUBPIXEL ||
	info->font->options.antialias == CAIRO_ANTIALIAS_BEST;

    /* If we are invoked by traps compositor, we keep what is in code
       otherwise, we handle non-subpixel/best directly in msaa
       compositor. */
    if (!via_msaa_compositor)
            status = _cairo_gl_composite_init (&setup, op, dst, TRUE);
    else if (info->font->options.antialias == CAIRO_ANTIALIAS_SUBPIXEL ||
       info->font->options.antialias == CAIRO_ANTIALIAS_BEST)
        status = _cairo_gl_composite_init (&setup, op, dst, TRUE);
    else
        status = _cairo_gl_composite_init (&setup, op, dst, FALSE);

    if (unlikely (status))
	goto FINISH;

    if (source == NULL) {
	    _cairo_gl_composite_set_solid_source (&setup, CAIRO_COLOR_WHITE);
    } else {
	    _cairo_gl_composite_set_source_operand (&setup,
						    source_to_operand (source));

    }

    if (setup.src.type == CAIRO_GL_OPERAND_CONSTANT)
        setup.src.use_color_attribute = TRUE;

    _cairo_gl_composite_set_clip (&setup, clip);

    for (i = 0; i < info->num_glyphs; i++) {
	cairo_scaled_glyph_t *scaled_glyph;
	cairo_gl_glyph_t *glyph;
	double x_offset, y_offset;
	double x1, x2, y1, y2;

	status = _cairo_scaled_glyph_lookup (info->font,
					     info->glyphs[i].index,
					     CAIRO_SCALED_GLYPH_INFO_SURFACE,
					     &scaled_glyph);
	if (unlikely (status))
	    goto FINISH;

	if (scaled_glyph->surface->width  == 0 ||
	    scaled_glyph->surface->height == 0)
	{
	    continue;
	}
	if (scaled_glyph->surface->format != last_format) {
	    status = cairo_gl_context_get_glyph_cache (ctx,
						       scaled_glyph->surface->format,
                                                       &cache);
            if (unlikely (status))
                goto FINISH;

	    last_format = scaled_glyph->surface->format;

	    /* In msaa compositor, clear operator needs component alpha,
	       we need to reset to FALSE if previously clear operator
	       has set it to TRUE. */
	    if (via_msaa_compositor) {
		if (op == CAIRO_OPERATOR_CLEAR || is_argb32)
		    cache->surface->operand.texture.attributes.has_component_alpha = TRUE;
		else
		    cache->surface->operand.texture.attributes.has_component_alpha = FALSE;
	    }
	    _cairo_gl_composite_set_mask_operand (&setup, &cache->surface->operand);
	    *has_component_alpha |= cache->surface->operand.texture.attributes.has_component_alpha;

	    /* XXX Shoot me. */
            status = _cairo_gl_composite_begin (&setup, &ctx);
            status = _cairo_gl_context_release (ctx, status);
	    if (unlikely (status))
		goto FINISH;
	}

	if (scaled_glyph->dev_private_key != cache) {
	    cairo_scaled_glyph_private_t *priv;

	    priv = _cairo_scaled_glyph_find_private (scaled_glyph, cache);
	    if (priv) {
		scaled_glyph->dev_private_key = cache;
		scaled_glyph->dev_private = cairo_container_of (priv,
								cairo_gl_glyph_t,
								base);
	    } else {
		status = _cairo_gl_glyph_cache_add_glyph (ctx, cache, scaled_glyph);

		if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
		    /* Cache is full, so flush existing prims and try again. */
		    _cairo_gl_composite_flush (ctx);
		    _cairo_gl_glyph_cache_unlock (cache);
		    status = _cairo_gl_glyph_cache_add_glyph (ctx, cache, scaled_glyph);
		}

		if (unlikely (_cairo_int_status_is_error (status)))
		    goto FINISH;
	    }
	}

	x_offset = scaled_glyph->surface->base.device_transform.x0;
	y_offset = scaled_glyph->surface->base.device_transform.y0;

	x1 = _cairo_lround (info->glyphs[i].x - x_offset - dst_x);
	y1 = _cairo_lround (info->glyphs[i].y - y_offset - dst_y);
	x2 = x1 + scaled_glyph->surface->width;
	y2 = y1 + scaled_glyph->surface->height;

	glyph = _cairo_gl_glyph_cache_lock (cache, scaled_glyph);
	_cairo_gl_composite_emit_glyph (ctx,
					x1, y1, x2, y2,
                                        glyph->p1.x, glyph->p1.y,
                                        glyph->p2.x, glyph->p2.y);
    }

    status = CAIRO_STATUS_SUCCESS;

  FINISH:
    status = _cairo_gl_context_release (ctx, status);

    _cairo_gl_composite_fini (&setup);
    return status;
}
Exemple #20
0
static cairo_status_t
render_glyphs (cairo_gl_surface_t *dst,
	       int dst_x, int dst_y,
	       cairo_operator_t op,
	       cairo_surface_t *source,
	       cairo_composite_glyphs_info_t *info,
	       cairo_bool_t *has_component_alpha,
	       cairo_clip_t *clip)
{
    cairo_format_t last_format = CAIRO_FORMAT_INVALID;
    cairo_gl_glyph_cache_t *cache = NULL;
    cairo_gl_context_t *ctx;
    cairo_gl_emit_glyph_t emit = NULL;
    cairo_gl_composite_t setup;
    cairo_int_status_t status;
    int i = 0;

    TRACE ((stderr, "%s (%d, %d)x(%d, %d)\n", __FUNCTION__,
	    info->extents.x, info->extents.y,
	    info->extents.width, info->extents.height));

    *has_component_alpha = FALSE;

    status = _cairo_gl_context_acquire (dst->base.device, &ctx);
    if (unlikely (status))
	return status;

    status = _cairo_gl_composite_init (&setup, op, dst, TRUE);
    if (unlikely (status))
	goto FINISH;

    if (source == NULL) {
	    _cairo_gl_composite_set_solid_source (&setup, CAIRO_COLOR_WHITE);
    } else {
	    _cairo_gl_composite_set_source_operand (&setup,
						    source_to_operand (source));

    }

    _cairo_gl_composite_set_clip (&setup, clip);

    for (i = 0; i < info->num_glyphs; i++) {
	cairo_scaled_glyph_t *scaled_glyph;
	cairo_gl_glyph_t *glyph;
	double x_offset, y_offset;
	double x1, x2, y1, y2;

	status = _cairo_scaled_glyph_lookup (info->font,
					     info->glyphs[i].index,
					     CAIRO_SCALED_GLYPH_INFO_SURFACE,
					     &scaled_glyph);
	if (unlikely (status))
	    goto FINISH;

	if (scaled_glyph->surface->width  == 0 ||
	    scaled_glyph->surface->height == 0)
	{
	    continue;
	}
	if (scaled_glyph->surface->format != last_format) {
	    status = cairo_gl_context_get_glyph_cache (ctx,
						       scaled_glyph->surface->format,
                                                       &cache);
            if (unlikely (status))
                goto FINISH;

	    last_format = scaled_glyph->surface->format;

	    _cairo_gl_composite_set_mask_operand (&setup, &cache->surface->operand);
	    *has_component_alpha |= cache->surface->operand.texture.attributes.has_component_alpha;

	    /* XXX Shoot me. */
            status = _cairo_gl_composite_begin (&setup, &ctx);
            status = _cairo_gl_context_release (ctx, status);
	    if (unlikely (status))
		goto FINISH;

	    emit = _cairo_gl_context_choose_emit_glyph (ctx);
	}

	if (scaled_glyph->dev_private_key != cache) {
	    cairo_scaled_glyph_private_t *priv;

	    priv = _cairo_scaled_glyph_find_private (scaled_glyph, cache);
	    if (priv) {
		scaled_glyph->dev_private_key = cache;
		scaled_glyph->dev_private = cairo_container_of (priv,
								cairo_gl_glyph_t,
								base);
	    } else {
		status = _cairo_gl_glyph_cache_add_glyph (ctx, cache, scaled_glyph);

		if (status == CAIRO_INT_STATUS_UNSUPPORTED) {
		    /* Cache is full, so flush existing prims and try again. */
		    _cairo_gl_composite_flush (ctx);
		    _cairo_gl_glyph_cache_unlock (cache);
		    status = _cairo_gl_glyph_cache_add_glyph (ctx, cache, scaled_glyph);
		}

		if (unlikely (_cairo_int_status_is_error (status)))
		    goto FINISH;
	    }
	}

	x_offset = scaled_glyph->surface->base.device_transform.x0;
	y_offset = scaled_glyph->surface->base.device_transform.y0;

	x1 = _cairo_lround (info->glyphs[i].x - x_offset - dst_x);
	y1 = _cairo_lround (info->glyphs[i].y - y_offset - dst_y);
	x2 = x1 + scaled_glyph->surface->width;
	y2 = y1 + scaled_glyph->surface->height;

	glyph = _cairo_gl_glyph_cache_lock (cache, scaled_glyph);
	assert (emit);
	emit (ctx,
	      x1, y1, x2, y2,
	      glyph->p1.x, glyph->p1.y,
	      glyph->p2.x, glyph->p2.y);
    }

    status = CAIRO_STATUS_SUCCESS;
  FINISH:
    status = _cairo_gl_context_release (ctx, status);

    _cairo_gl_composite_fini (&setup);
    return status;
}