static cairo_status_t
_cairo_recording_surface_finish (void *abstract_surface)
{
    cairo_recording_surface_t *recording_surface = abstract_surface;
    cairo_command_t **elements;
    int i, num_elements;

    num_elements = recording_surface->commands.num_elements;
    elements = _cairo_array_index (&recording_surface->commands, 0);
    for (i = 0; i < num_elements; i++) {
	cairo_command_t *command = elements[i];

	switch (command->header.type) {
	case CAIRO_COMMAND_PAINT:
	    _cairo_pattern_fini (&command->paint.source.base);
	    break;

	case CAIRO_COMMAND_MASK:
	    _cairo_pattern_fini (&command->mask.source.base);
	    _cairo_pattern_fini (&command->mask.mask.base);
	    break;

	case CAIRO_COMMAND_STROKE:
	    _cairo_pattern_fini (&command->stroke.source.base);
	    _cairo_path_fixed_fini (&command->stroke.path);
	    _cairo_stroke_style_fini (&command->stroke.style);
	    break;

	case CAIRO_COMMAND_FILL:
	    _cairo_pattern_fini (&command->fill.source.base);
	    _cairo_path_fixed_fini (&command->fill.path);
	    break;

	case CAIRO_COMMAND_SHOW_TEXT_GLYPHS:
	    _cairo_pattern_fini (&command->show_text_glyphs.source.base);
	    free (command->show_text_glyphs.utf8);
	    free (command->show_text_glyphs.glyphs);
	    free (command->show_text_glyphs.clusters);
	    cairo_scaled_font_destroy (command->show_text_glyphs.scaled_font);
	    break;

	default:
	    ASSERT_NOT_REACHED;
	}

	_cairo_clip_fini (&command->header.clip);
	free (command);
    }

    _cairo_array_fini (&recording_surface->commands);
    _cairo_clip_fini (&recording_surface->clip);

    return CAIRO_STATUS_SUCCESS;
}
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;
}
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;
}
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;
}
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;
}
Ejemplo n.º 6
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;
}
cairo_int_status_t
_cairo_meta_surface_replay (cairo_surface_t *surface,
			    cairo_surface_t *target)
{
    cairo_meta_surface_t *meta;
    cairo_command_t *command, **elements;
    int i, num_elements;
    cairo_int_status_t status;
    cairo_traps_t traps;
    cairo_clip_t clip;

    meta = (cairo_meta_surface_t *) surface;
    status = CAIRO_STATUS_SUCCESS;

    _cairo_clip_init (&clip, target);    

    num_elements = meta->commands.num_elements;
    elements = (cairo_command_t **) meta->commands.elements;
    for (i = 0; i < num_elements; i++) {
	command = elements[i];
	switch (command->type) {
	case CAIRO_COMMAND_COMPOSITE:
	    status = _cairo_surface_set_clip (target, &clip);
	    if (status)
		break;

	    status = _cairo_surface_composite
		(command->composite.operator,
		 &command->composite.src_pattern.base,
		 command->composite.mask_pattern_pointer,
		 target,
		 command->composite.src_x,
		 command->composite.src_y,
		 command->composite.mask_x,
		 command->composite.mask_y,
		 command->composite.dst_x,
		 command->composite.dst_y,
		 command->composite.width,
		 command->composite.height);
	    break;

	case CAIRO_COMMAND_FILL_RECTANGLES:
	    status = _cairo_surface_set_clip (target, &clip);
	    if (status)
		break;

	    status = _cairo_surface_fill_rectangles
		(target,
		 command->fill_rectangles.operator,
		 &command->fill_rectangles.color,
		 command->fill_rectangles.rects,
		 command->fill_rectangles.num_rects);
	    break;

	case CAIRO_COMMAND_COMPOSITE_TRAPEZOIDS:
	    status = _cairo_surface_set_clip (target, &clip);
	    if (status)
		break;

	    status = _cairo_surface_composite_trapezoids
		(command->composite_trapezoids.operator,
		 &command->composite_trapezoids.pattern.base,
		 target,
		 command->composite_trapezoids.antialias,
		 command->composite_trapezoids.x_src,
		 command->composite_trapezoids.y_src,
		 command->composite_trapezoids.x_dst,
		 command->composite_trapezoids.y_dst,
		 command->composite_trapezoids.width,
		 command->composite_trapezoids.height,
		 command->composite_trapezoids.traps,
		 command->composite_trapezoids.num_traps);
	    break;

	case CAIRO_COMMAND_INTERSECT_CLIP_PATH:
	    /* XXX Meta surface clipping is broken and requires some
	     * cairo-gstate.c rewriting.  Work around it for now. */
	    if (command->intersect_clip_path.path_pointer == NULL)
		status = _cairo_clip_reset (&clip);
	    else
		status = _cairo_clip_clip (&clip,
					   command->intersect_clip_path.path_pointer,
					   command->intersect_clip_path.fill_rule,
					   command->intersect_clip_path.tolerance,
					   command->intersect_clip_path.antialias,
					   target);
	    break;

	case CAIRO_COMMAND_SHOW_GLYPHS:
	    status = _cairo_surface_set_clip (target, &clip);
	    if (status)
		break;

	    status = _cairo_surface_show_glyphs
		(command->show_glyphs.scaled_font,
		 command->show_glyphs.operator,
		 &command->show_glyphs.pattern.base,
		 target,
		 command->show_glyphs.source_x,
		 command->show_glyphs.source_y,
		 command->show_glyphs.dest_x,
		 command->show_glyphs.dest_y,
		 command->show_glyphs.width,
		 command->show_glyphs.height,
		 command->show_glyphs.glyphs,
		 command->show_glyphs.num_glyphs);
	    if (status != CAIRO_INT_STATUS_UNSUPPORTED)
		break;
	    
	    status = (*command->show_glyphs.scaled_font->backend->
		      show_glyphs) (command->show_glyphs.scaled_font,
				    command->show_glyphs.operator,
				    &command->show_glyphs.pattern.base,
				    target,
				    command->show_glyphs.source_x,
				    command->show_glyphs.source_y,
				    command->show_glyphs.dest_x,
				    command->show_glyphs.dest_y,
				    command->show_glyphs.width,
				    command->show_glyphs.height,
				    command->show_glyphs.glyphs,
				    command->show_glyphs.num_glyphs);

	    break;

	case CAIRO_COMMAND_FILL_PATH:
	    status = _cairo_surface_set_clip (target, &clip);
	    if (status)
		break;

	    status = _cairo_surface_fill_path (command->fill_path.operator,
					       &command->fill_path.pattern.base,
					       target,
					       &command->fill_path.path,
					       command->fill_path.fill_rule,
					       command->fill_path.tolerance);
	    if (status != CAIRO_INT_STATUS_UNSUPPORTED)
		break;

	    _cairo_traps_init (&traps);

	    status = _cairo_path_fixed_fill_to_traps (&command->fill_path.path,
						      command->fill_path.fill_rule,
						      command->fill_path.tolerance,
						      &traps);
	    if (status) {
		_cairo_traps_fini (&traps);
		break;
	    }

	    status = _cairo_surface_clip_and_composite_trapezoids (&command->fill_path.pattern.base,
								   command->fill_path.operator,
								   target,
								   &traps,
								   &clip,
								   command->fill_path.antialias);

	    _cairo_traps_fini (&traps);
	    break;

	default:
	    ASSERT_NOT_REACHED;
	}

	if (status)
	    break;
    }

    _cairo_clip_fini (&clip);

    return status;
}