Exemplo n.º 1
0
cairo_status_t
_cairo_xlib_screen_get_visual_info (cairo_xlib_screen_info_t *info,
				    Visual *visual,
				    cairo_xlib_visual_info_t **out)
{
    Display *dpy = info->display->display;
    cairo_xlib_visual_info_t **visuals, *ret = NULL;
    cairo_status_t status;
    int i, n_visuals;

    CAIRO_MUTEX_LOCK (info->mutex);
    visuals = _cairo_array_index (&info->visuals, 0);
    n_visuals = _cairo_array_num_elements (&info->visuals);
    for (i = 0; i < n_visuals; i++) {
	if (visuals[i]->visualid == visual->visualid) {
	    ret = visuals[i];
	    break;
	}
    }
    CAIRO_MUTEX_UNLOCK (info->mutex);

    if (ret != NULL) {
	*out = ret;
	return CAIRO_STATUS_SUCCESS;
    }

    status = _cairo_xlib_visual_info_create (dpy,
					     XScreenNumberOfScreen (info->screen),
					     visual->visualid,
					     &ret);
    if (status)
	return status;

    CAIRO_MUTEX_LOCK (info->mutex);
    if (n_visuals != _cairo_array_num_elements (&info->visuals)) {
	/* check that another thread has not added our visual */
	int new_visuals = _cairo_array_num_elements (&info->visuals);
	visuals = _cairo_array_index (&info->visuals, 0);
	for (i = n_visuals; i < new_visuals; i++) {
	    if (visuals[i]->visualid == visual->visualid) {
		_cairo_xlib_visual_info_destroy (dpy, ret);
		ret = visuals[i];
		break;
	    }
	}
	if (i == new_visuals)
	    status = _cairo_array_append (&info->visuals, &ret);
    } else
	status = _cairo_array_append (&info->visuals, &ret);
    CAIRO_MUTEX_UNLOCK (info->mutex);

    if (status) {
	_cairo_xlib_visual_info_destroy (dpy, ret);
	return status;
    }

    *out = ret;
    return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
_cairo_meta_surface_fill_rectangles (void			*abstract_surface,
				     cairo_operator_t		operator,
				     const cairo_color_t	*color,
				     cairo_rectangle_t		*rects,
				     int			num_rects)
{
    cairo_meta_surface_t *meta = abstract_surface;
    cairo_command_fill_rectangles_t *command;

    command = malloc (sizeof (cairo_command_fill_rectangles_t));
    if (command == NULL)
	return CAIRO_STATUS_NO_MEMORY;

    command->type = CAIRO_COMMAND_FILL_RECTANGLES;
    command->operator = operator;
    command->color = *color;

    command->rects = malloc (sizeof (cairo_rectangle_t) * num_rects);
    if (command->rects == NULL) {
	free (command);
        return CAIRO_STATUS_NO_MEMORY;
    }
    memcpy (command->rects, rects, sizeof (cairo_rectangle_t) * num_rects);

    command->num_rects = num_rects;

    if (_cairo_array_append (&meta->commands, &command, 1) == NULL) {
	free (command->rects);
	free (command);
	return CAIRO_STATUS_NO_MEMORY;
    }

    return CAIRO_STATUS_SUCCESS;
}
Exemplo n.º 3
0
void
cairo_tee_surface_add (cairo_surface_t *abstract_surface,
		       cairo_surface_t *target)
{
    cairo_tee_surface_t *surface;
    cairo_surface_wrapper_t slave;
    cairo_status_t status;

    if (unlikely (abstract_surface->status))
	return;

    if (abstract_surface->backend != &cairo_tee_surface_backend) {
	status = _cairo_surface_set_error (abstract_surface,
					   _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH));
	return;
    }

    if (unlikely (target->status)) {
	status = _cairo_surface_set_error (abstract_surface, target->status);
	return;
    }

    surface = (cairo_tee_surface_t *) abstract_surface;

    _cairo_surface_wrapper_init (&slave, target);
    status = _cairo_array_append (&surface->slaves, &slave);
    if (unlikely (status)) {
	_cairo_surface_wrapper_fini (&slave);
	status = _cairo_surface_set_error (&surface->base, status);
    }
}
static cairo_int_status_t
_cairo_recording_surface_stroke (void			*abstract_surface,
				 cairo_operator_t	 op,
				 const cairo_pattern_t	*source,
				 cairo_path_fixed_t	*path,
				 const cairo_stroke_style_t	*style,
				 const cairo_matrix_t		*ctm,
				 const cairo_matrix_t		*ctm_inverse,
				 double			 tolerance,
				 cairo_antialias_t	 antialias,
				 cairo_clip_t		*clip)
{
    cairo_status_t status;
    cairo_recording_surface_t *recording_surface = abstract_surface;
    cairo_command_stroke_t *command;

    command = malloc (sizeof (cairo_command_stroke_t));
    if (unlikely (command == NULL))
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);

    status = _command_init (recording_surface,
			    &command->header, CAIRO_COMMAND_STROKE, op, clip);
    if (unlikely (status))
	goto CLEANUP_COMMAND;

    status = _cairo_pattern_init_snapshot (&command->source.base, source);
    if (unlikely (status))
	goto CLEANUP_COMMAND;

    status = _cairo_path_fixed_init_copy (&command->path, path);
    if (unlikely (status))
	goto CLEANUP_SOURCE;

    status = _cairo_stroke_style_init_copy (&command->style, style);
    if (unlikely (status))
	goto CLEANUP_PATH;

    command->ctm = *ctm;
    command->ctm_inverse = *ctm_inverse;
    command->tolerance = tolerance;
    command->antialias = antialias;

    status = _cairo_array_append (&recording_surface->commands, &command);
    if (unlikely (status))
	goto CLEANUP_STYLE;

    return CAIRO_STATUS_SUCCESS;

  CLEANUP_STYLE:
    _cairo_stroke_style_fini (&command->style);
  CLEANUP_PATH:
    _cairo_path_fixed_fini (&command->path);
  CLEANUP_SOURCE:
    _cairo_pattern_fini (&command->source.base);
  CLEANUP_COMMAND:
    _cairo_clip_fini (&command->header.clip);
    free (command);
    return status;
}
Exemplo n.º 5
0
static cairo_int_status_t
_cairo_meta_surface_stroke (void			*abstract_surface,
			    cairo_operator_t		 op,
			    cairo_pattern_t		*source,
			    cairo_path_fixed_t		*path,
			    cairo_stroke_style_t	*style,
			    cairo_matrix_t		*ctm,
			    cairo_matrix_t		*ctm_inverse,
			    double			 tolerance,
			    cairo_antialias_t		 antialias)
{
    cairo_status_t status;
    cairo_meta_surface_t *meta = abstract_surface;
    cairo_command_stroke_t *command;

    command = malloc (sizeof (cairo_command_stroke_t));
    if (command == NULL)
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);

    command->header.type = CAIRO_COMMAND_STROKE;
    command->header.region = CAIRO_META_REGION_ALL;
    command->op = op;

    status = _cairo_pattern_init_snapshot (&command->source.base, source);
    if (status)
	goto CLEANUP_COMMAND;

    status = _cairo_path_fixed_init_copy (&command->path, path);
    if (status)
	goto CLEANUP_SOURCE;

    status = _cairo_stroke_style_init_copy (&command->style, style);
    if (status)
	goto CLEANUP_PATH;

    command->ctm = *ctm;
    command->ctm_inverse = *ctm_inverse;
    command->tolerance = tolerance;
    command->antialias = antialias;

    status = _cairo_array_append (&meta->commands, &command);
    if (status)
	goto CLEANUP_STYLE;

    return CAIRO_STATUS_SUCCESS;

  CLEANUP_STYLE:
    _cairo_stroke_style_fini (&command->style);
  CLEANUP_PATH:
    _cairo_path_fixed_fini (&command->path);
  CLEANUP_SOURCE:
    _cairo_pattern_fini (&command->source.base);
  CLEANUP_COMMAND:
    free (command);
    return status;
}
Exemplo n.º 6
0
static cairo_int_status_t
_cairo_gl_composite_append_vertex_indices (cairo_gl_context_t	*ctx,
					   int			 number_of_new_indices,
					   cairo_bool_t		 is_connected)
{
    cairo_int_status_t status = CAIRO_INT_STATUS_SUCCESS;
    cairo_array_t *indices = &ctx->tristrip_indices;
    int number_of_indices = _cairo_array_num_elements (indices);
    unsigned short current_vertex_index = 0;
    int i;

    assert (number_of_new_indices > 0);

    /* If any preexisting triangle triangle strip indices exist on this
       context, we insert a set of degenerate triangles from the last
       preexisting vertex to our first one. */
    if (number_of_indices > 0 && is_connected) {
	const unsigned short *indices_array = _cairo_array_index_const (indices, 0);
	current_vertex_index = indices_array[number_of_indices - 1];

	status = _cairo_array_append (indices, &current_vertex_index);
	if (unlikely (status))
	    return status;

	current_vertex_index++;
	status =_cairo_array_append (indices, &current_vertex_index);
	if (unlikely (status))
	    return status;
    } else
	current_vertex_index = (unsigned short) number_of_indices;

    for (i = 0; i < number_of_new_indices; i++) {
	status = _cairo_array_append (indices, &current_vertex_index);
	current_vertex_index++;
	if (unlikely (status))
	    return status;
    }

    return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
_cairo_meta_surface_show_glyphs (cairo_scaled_font_t	*scaled_font,
				 cairo_operator_t	operator,
				 cairo_pattern_t	*pattern,
				 void			*abstract_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_meta_surface_t *meta = abstract_surface;
    cairo_command_show_glyphs_t *command;

    command = malloc (sizeof (cairo_command_show_glyphs_t));
    if (command == NULL)
	return CAIRO_STATUS_NO_MEMORY;

    command->type = CAIRO_COMMAND_SHOW_GLYPHS;
    command->scaled_font = cairo_scaled_font_reference (scaled_font);
    command->operator = operator;
    _cairo_pattern_init_copy (&command->pattern.base, pattern);
    command->source_x = source_x;
    command->source_y = source_y;
    command->dest_x = dest_x;
    command->dest_y = dest_y;
    command->width = width;
    command->height = height;

    command->glyphs = malloc (sizeof (cairo_glyph_t) * num_glyphs);
    if (command->glyphs == NULL) {
	_cairo_pattern_fini (&command->pattern.base);
	free (command);
        return CAIRO_STATUS_NO_MEMORY;
    }
    memcpy (command->glyphs, glyphs, sizeof (cairo_glyph_t) * num_glyphs);

    command->num_glyphs = num_glyphs;

    if (_cairo_array_append (&meta->commands, &command, 1) == NULL) {
	_cairo_pattern_fini (&command->pattern.base);
	free (command->glyphs);
	free (command);
	return CAIRO_STATUS_NO_MEMORY;
    }

    return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
_cairo_meta_surface_composite_trapezoids (cairo_operator_t	operator,
					  cairo_pattern_t	*pattern,
					  void			*abstract_surface,
					  cairo_antialias_t	antialias,
					  int			x_src,
					  int			y_src,
					  int			x_dst,
					  int			y_dst,
					  unsigned int		width,
					  unsigned int		height,
					  cairo_trapezoid_t	*traps,
					  int			num_traps)
{
    cairo_meta_surface_t *meta = abstract_surface;
    cairo_command_composite_trapezoids_t *command;

    command = malloc (sizeof (cairo_command_composite_trapezoids_t));
    if (command == NULL)
	return CAIRO_STATUS_NO_MEMORY;

    command->type = CAIRO_COMMAND_COMPOSITE_TRAPEZOIDS;
    command->operator = operator;
    _cairo_pattern_init_copy (&command->pattern.base, pattern);
    command->antialias = antialias;
    command->x_src = x_src;
    command->y_src = y_src;
    command->x_dst = x_dst;
    command->y_dst = y_dst;
    command->width = width;
    command->height = height;

    command->traps = malloc (sizeof (cairo_trapezoid_t) * num_traps);
    if (command->traps == NULL) {
	_cairo_pattern_fini (&command->pattern.base);
	free (command);
        return CAIRO_STATUS_NO_MEMORY;
    }
    memcpy (command->traps, traps, sizeof (cairo_trapezoid_t) * num_traps);

    command->num_traps = num_traps;

    if (_cairo_array_append (&meta->commands, &command, 1) == NULL) {
	_cairo_pattern_fini (&command->pattern.base);
	free (command->traps);
	free (command);
	return CAIRO_STATUS_NO_MEMORY;
    }

    return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
_cairo_meta_surface_composite (cairo_operator_t	operator,
			       cairo_pattern_t	*src_pattern,
			       cairo_pattern_t	*mask_pattern,
			       void		*abstract_surface,
			       int		src_x,
			       int		src_y,
			       int		mask_x,
			       int		mask_y,
			       int		dst_x,
			       int		dst_y,
			       unsigned int	width,
			       unsigned int	height)
{
    cairo_meta_surface_t *meta = abstract_surface;
    cairo_command_composite_t *command;

    command = malloc (sizeof (cairo_command_composite_t));
    if (command == NULL)
	return CAIRO_STATUS_NO_MEMORY;

    command->type = CAIRO_COMMAND_COMPOSITE;
    command->operator = operator;
    _cairo_pattern_init_copy (&command->src_pattern.base, src_pattern);
    if (mask_pattern) {
	_cairo_pattern_init_copy (&command->mask_pattern.base, mask_pattern);
	command->mask_pattern_pointer = &command->mask_pattern.base;
    } else {
	command->mask_pattern_pointer = NULL;
    }
	
    command->src_x = src_x;
    command->src_y = src_y;
    command->mask_x = mask_x;
    command->mask_y = mask_y;
    command->dst_x = dst_x;
    command->dst_y = dst_y;
    command->width = width;
    command->height = height;

    if (_cairo_array_append (&meta->commands, &command, 1) == NULL) {
	_cairo_pattern_fini (&command->src_pattern.base);
	_cairo_pattern_fini (command->mask_pattern_pointer);
	free (command);
	return CAIRO_STATUS_NO_MEMORY;
    }

    return CAIRO_STATUS_SUCCESS;
}
Exemplo n.º 10
0
/**
 * _cairo_user_data_array_set_data:
 * @array: a #cairo_user_data_array_t
 * @key: the address of a #cairo_user_data_key_t to attach the user data to
 * @user_data: the user data to attach
 * @destroy: a #cairo_destroy_func_t which will be called when the
 * user data array is destroyed or when new user data is attached using the
 * same key.
 *
 * Attaches user data to a user data array.  To remove user data,
 * call this function with the key that was used to set it and %NULL
 * for @data.
 *
 * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY if a
 * slot could not be allocated for the user data.
 **/
cairo_status_t
_cairo_user_data_array_set_data (cairo_user_data_array_t     *array,
				 const cairo_user_data_key_t *key,
				 void			     *user_data,
				 cairo_destroy_func_t	      destroy)
{
    cairo_status_t status;
    int i, num_slots;
    cairo_user_data_slot_t *slots, *slot, new_slot;

    if (user_data) {
	new_slot.key = key;
	new_slot.user_data = user_data;
	new_slot.destroy = destroy;
    } else {
	new_slot.key = NULL;
	new_slot.user_data = NULL;
	new_slot.destroy = NULL;
    }

    slot = NULL;
    num_slots = array->num_elements;
    slots = _cairo_array_index (array, 0);
    for (i = 0; i < num_slots; i++) {
	if (slots[i].key == key) {
	    slot = &slots[i];
	    if (slot->destroy && slot->user_data)
		slot->destroy (slot->user_data);
	    break;
	}
	if (user_data && slots[i].user_data == NULL) {
	    slot = &slots[i];	/* Have to keep searching for an exact match */
	}
    }

    if (slot) {
	*slot = new_slot;
	return CAIRO_STATUS_SUCCESS;
    }

    status = _cairo_array_append (array, &new_slot);
    if (status)
	return status;

    return CAIRO_STATUS_SUCCESS;
}
Exemplo n.º 11
0
static cairo_int_status_t
_cairo_meta_surface_intersect_clip_path (void		    *dst,
					 cairo_path_fixed_t *path,
					 cairo_fill_rule_t   fill_rule,
					 double		     tolerance,
					 cairo_antialias_t   antialias)
{
    cairo_meta_surface_t *meta = dst;
    cairo_command_intersect_clip_path_t *command;
    cairo_status_t status;

    command = malloc (sizeof (cairo_command_intersect_clip_path_t));
    if (command == NULL)
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);

    command->header.type = CAIRO_COMMAND_INTERSECT_CLIP_PATH;
    command->header.region = CAIRO_META_REGION_ALL;

    if (path) {
	status = _cairo_path_fixed_init_copy (&command->path, path);
	if (status) {
	    free (command);
	    return status;
	}
	command->path_pointer = &command->path;
	meta->is_clipped = TRUE;
    } else {
	command->path_pointer = NULL;
	meta->is_clipped = FALSE;
    }
    command->fill_rule = fill_rule;
    command->tolerance = tolerance;
    command->antialias = antialias;

    status = _cairo_array_append (&meta->commands, &command);
    if (status) {
	if (path)
	    _cairo_path_fixed_fini (&command->path);
	free (command);
	return status;
    }

    return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
_cairo_recording_surface_mask (void			*abstract_surface,
			       cairo_operator_t		 op,
			       const cairo_pattern_t	*source,
			       const cairo_pattern_t	*mask,
			       cairo_clip_t		*clip)
{
    cairo_status_t status;
    cairo_recording_surface_t *recording_surface = abstract_surface;
    cairo_command_mask_t *command;

    command = malloc (sizeof (cairo_command_mask_t));
    if (unlikely (command == NULL))
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);

    status = _command_init (recording_surface,
			    &command->header, CAIRO_COMMAND_MASK, op, clip);
    if (unlikely (status))
	goto CLEANUP_COMMAND;

    status = _cairo_pattern_init_snapshot (&command->source.base, source);
    if (unlikely (status))
	goto CLEANUP_COMMAND;

    status = _cairo_pattern_init_snapshot (&command->mask.base, mask);
    if (unlikely (status))
	goto CLEANUP_SOURCE;

    status = _cairo_array_append (&recording_surface->commands, &command);
    if (unlikely (status))
	goto CLEANUP_MASK;

    return CAIRO_STATUS_SUCCESS;

  CLEANUP_MASK:
    _cairo_pattern_fini (&command->mask.base);
  CLEANUP_SOURCE:
    _cairo_pattern_fini (&command->source.base);
  CLEANUP_COMMAND:
    _cairo_clip_fini (&command->header.clip);
    free (command);
    return status;
}
Exemplo n.º 13
0
static cairo_status_t
cairo_truetype_font_check_boundary (cairo_truetype_font_t *font,
				    unsigned long          boundary)
{
    cairo_status_t status;

    if (boundary - font->last_offset > SFNT_STRING_MAX_LENGTH)
    {
        status = _cairo_array_append (&font->string_offsets,
				      &font->last_boundary);
	if (status)
	    return status;

        font->last_offset = font->last_boundary;
    }
    font->last_boundary = boundary;

    return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
_cairo_recording_surface_paint (void			  *abstract_surface,
				cairo_operator_t	   op,
				const cairo_pattern_t	  *source,
				cairo_clip_t		  *clip)
{
    cairo_status_t status;
    cairo_recording_surface_t *recording_surface = abstract_surface;
    cairo_command_paint_t *command;

    command = malloc (sizeof (cairo_command_paint_t));
    if (unlikely (command == NULL))
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);

    status = _command_init (recording_surface,
			    &command->header, CAIRO_COMMAND_PAINT, op, clip);
    if (unlikely (status))
	goto CLEANUP_COMMAND;

    status = _cairo_pattern_init_snapshot (&command->source.base, source);
    if (unlikely (status))
	goto CLEANUP_COMMAND;

    status = _cairo_array_append (&recording_surface->commands, &command);
    if (unlikely (status))
	goto CLEANUP_SOURCE;

    /* An optimisation that takes care to not replay what was done
     * before surface is cleared. We don't erase recorded commands
     * since we may have earlier snapshots of this surface. */
    if (op == CAIRO_OPERATOR_CLEAR && clip == NULL)
	recording_surface->replay_start_idx = recording_surface->commands.num_elements;

    return CAIRO_STATUS_SUCCESS;

  CLEANUP_SOURCE:
    _cairo_pattern_fini (&command->source.base);
  CLEANUP_COMMAND:
    _cairo_clip_fini (&command->header.clip);
    free (command);
    return status;
}
Exemplo n.º 15
0
static cairo_int_status_t
_cairo_meta_surface_mask (void			*abstract_surface,
			  cairo_operator_t	 op,
			  cairo_pattern_t	*source,
			  cairo_pattern_t	*mask)
{
    cairo_status_t status;
    cairo_meta_surface_t *meta = abstract_surface;
    cairo_command_mask_t *command;

    command = malloc (sizeof (cairo_command_mask_t));
    if (command == NULL)
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);

    command->header.type = CAIRO_COMMAND_MASK;
    command->header.region = CAIRO_META_REGION_ALL;
    command->op = op;

    status = _cairo_pattern_init_snapshot (&command->source.base, source);
    if (status)
	goto CLEANUP_COMMAND;

    status = _cairo_pattern_init_snapshot (&command->mask.base, mask);
    if (status)
	goto CLEANUP_SOURCE;

    status = _cairo_array_append (&meta->commands, &command);
    if (status)
	goto CLEANUP_MASK;

    return CAIRO_STATUS_SUCCESS;

  CLEANUP_MASK:
    _cairo_pattern_fini (&command->mask.base);
  CLEANUP_SOURCE:
    _cairo_pattern_fini (&command->source.base);
  CLEANUP_COMMAND:
    free (command);
    return status;
}
Exemplo n.º 16
0
static cairo_int_status_t
_cairo_meta_surface_paint (void			*abstract_surface,
			   cairo_operator_t	 op,
			   cairo_pattern_t	*source)
{
    cairo_status_t status;
    cairo_meta_surface_t *meta = abstract_surface;
    cairo_command_paint_t *command;

    command = malloc (sizeof (cairo_command_paint_t));
    if (command == NULL)
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);

    command->header.type = CAIRO_COMMAND_PAINT;
    command->header.region = CAIRO_META_REGION_ALL;
    command->op = op;

    status = _cairo_pattern_init_snapshot (&command->source.base, source);
    if (status)
	goto CLEANUP_COMMAND;

    status = _cairo_array_append (&meta->commands, &command);
    if (status)
	goto CLEANUP_SOURCE;

    /* An optimisation that takes care to not replay what was done
     * before surface is cleared. We don't erase recorded commands
     * since we may have earlier snapshots of this surface. */
    if (op == CAIRO_OPERATOR_CLEAR && !meta->is_clipped)
	meta->replay_start_idx = meta->commands.num_elements;

    return CAIRO_STATUS_SUCCESS;

  CLEANUP_SOURCE:
    _cairo_pattern_fini (&command->source.base);
  CLEANUP_COMMAND:
    free (command);
    return status;
}
static cairo_int_status_t
_cairo_meta_surface_fill_path (cairo_operator_t	   operator,
			       cairo_pattern_t	  *pattern,
			       void		  *abstract_surface,
			       cairo_path_fixed_t *path,
			       cairo_fill_rule_t   fill_rule,
			       double		   tolerance)
{
    cairo_meta_surface_t *meta = abstract_surface;
    cairo_command_fill_path_t *command;
    cairo_status_t status;

    command = malloc (sizeof (cairo_command_fill_path_t));
    if (command == NULL)
	return CAIRO_STATUS_NO_MEMORY;

    command->type = CAIRO_COMMAND_FILL_PATH;
    command->operator = operator;
    _cairo_pattern_init_copy (&command->pattern.base, pattern);
    status = _cairo_path_fixed_init_copy (&command->path, path);
    if (status) {
	_cairo_pattern_fini (&command->pattern.base);
	free (command);
	return CAIRO_STATUS_NO_MEMORY;
    }	
    command->fill_rule = fill_rule;
    command->tolerance = tolerance;

    if (_cairo_array_append (&meta->commands, &command, 1) == NULL) {
	_cairo_path_fixed_fini (&command->path);
	_cairo_pattern_fini (&command->pattern.base);
	free (command);
	return CAIRO_STATUS_NO_MEMORY;
    }

    return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
_cairo_recording_surface_show_text_glyphs (void				*abstract_surface,
					   cairo_operator_t		 op,
					   const cairo_pattern_t	*source,
					   const char			*utf8,
					   int				 utf8_len,
					   cairo_glyph_t		*glyphs,
					   int				 num_glyphs,
					   const cairo_text_cluster_t	*clusters,
					   int				 num_clusters,
					   cairo_text_cluster_flags_t	 cluster_flags,
					   cairo_scaled_font_t		*scaled_font,
					   cairo_clip_t			*clip)
{
    cairo_status_t status;
    cairo_recording_surface_t *recording_surface = abstract_surface;
    cairo_command_show_text_glyphs_t *command;

    command = malloc (sizeof (cairo_command_show_text_glyphs_t));
    if (unlikely (command == NULL))
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);

    status = _command_init (recording_surface,
			    &command->header, CAIRO_COMMAND_SHOW_TEXT_GLYPHS,
			    op, clip);
    if (unlikely (status))
	goto CLEANUP_COMMAND;

    status = _cairo_pattern_init_snapshot (&command->source.base, source);
    if (unlikely (status))
	goto CLEANUP_COMMAND;

    command->utf8 = NULL;
    command->utf8_len = utf8_len;
    command->glyphs = NULL;
    command->num_glyphs = num_glyphs;
    command->clusters = NULL;
    command->num_clusters = num_clusters;

    if (utf8_len) {
	command->utf8 = malloc (utf8_len);
	if (unlikely (command->utf8 == NULL)) {
	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
	    goto CLEANUP_ARRAYS;
	}
	memcpy (command->utf8, utf8, utf8_len);
    }
    if (num_glyphs) {
	command->glyphs = _cairo_malloc_ab (num_glyphs, sizeof (glyphs[0]));
	if (unlikely (command->glyphs == NULL)) {
	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
	    goto CLEANUP_ARRAYS;
	}
	memcpy (command->glyphs, glyphs, sizeof (glyphs[0]) * num_glyphs);
    }
    if (num_clusters) {
	command->clusters = _cairo_malloc_ab (num_clusters, sizeof (clusters[0]));
	if (unlikely (command->clusters == NULL)) {
	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
	    goto CLEANUP_ARRAYS;
	}
	memcpy (command->clusters, clusters, sizeof (clusters[0]) * num_clusters);
    }

    command->cluster_flags = cluster_flags;

    command->scaled_font = cairo_scaled_font_reference (scaled_font);

    status = _cairo_array_append (&recording_surface->commands, &command);
    if (unlikely (status))
	goto CLEANUP_SCALED_FONT;

    return CAIRO_STATUS_SUCCESS;

  CLEANUP_SCALED_FONT:
    cairo_scaled_font_destroy (command->scaled_font);
  CLEANUP_ARRAYS:
    free (command->utf8);
    free (command->glyphs);
    free (command->clusters);

    _cairo_pattern_fini (&command->source.base);
  CLEANUP_COMMAND:
    _cairo_clip_fini (&command->header.clip);
    free (command);
    return status;
}