static cairo_status_t
_recording_surface_get_ink_bbox (cairo_recording_surface_t *surface,
				 cairo_box_t *bbox,
				 const cairo_matrix_t *transform)
{
    cairo_surface_t *null_surface;
    cairo_surface_t *analysis_surface;
    cairo_status_t status;

    null_surface = _cairo_null_surface_create (surface->content);
    analysis_surface = _cairo_analysis_surface_create (null_surface);
    cairo_surface_destroy (null_surface);

    status = analysis_surface->status;
    if (unlikely (status))
	return status;

    if (transform != NULL)
	_cairo_analysis_surface_set_ctm (analysis_surface, transform);

    status = _cairo_recording_surface_replay (&surface->base, analysis_surface);
    _cairo_analysis_surface_get_bounding_box (analysis_surface, bbox);
    cairo_surface_destroy (analysis_surface);

    return status;
}
static cairo_status_t
_cairo_paginated_surface_acquire_source_image (void	       *abstract_surface,
					       cairo_image_surface_t **image_out,
					       void		   **image_extra)
{
    cairo_paginated_surface_t *surface = abstract_surface;
    cairo_bool_t is_bounded;
    cairo_surface_t *image;
    cairo_status_t status;
    cairo_rectangle_int_t extents;

    is_bounded = _cairo_surface_get_extents (surface->target, &extents);
    if (! is_bounded)
	return (cairo_status_t)CAIRO_INT_STATUS_UNSUPPORTED;

    image = _cairo_paginated_surface_create_image_surface (surface,
							   extents.width,
							   extents.height);

    status = _cairo_recording_surface_replay (surface->recording_surface, image);
    if (unlikely (status)) {
	cairo_surface_destroy (image);
	return status;
    }

    *image_out = (cairo_image_surface_t*) image;
    *image_extra = NULL;

    return CAIRO_STATUS_SUCCESS;
}
예제 #3
0
cairo_status_t
cairo_xml_for_recording_surface (cairo_device_t	 *device,
				 cairo_surface_t *recording_surface)
{
    cairo_box_t bbox;
    cairo_rectangle_int_t extents;
    cairo_surface_t *surface;
    cairo_xml_t *xml;
    cairo_status_t status;

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

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

    if (unlikely (device->backend->type != CAIRO_DEVICE_TYPE_XML))
	return _cairo_error (CAIRO_STATUS_DEVICE_TYPE_MISMATCH);

    if (unlikely (! _cairo_surface_is_recording (recording_surface)))
	return _cairo_error (CAIRO_STATUS_SURFACE_TYPE_MISMATCH);

    status = _cairo_recording_surface_get_bbox ((cairo_recording_surface_t *) recording_surface,
						&bbox, NULL);
    if (unlikely (status))
	return status;

    _cairo_box_round_to_rectangle (&bbox, &extents);
    surface = _cairo_xml_surface_create_internal (device,
						  recording_surface->content,
						  extents.width,
						  extents.height);
    if (unlikely (surface->status))
	return surface->status;

    xml = (cairo_xml_t *) device;

    _cairo_xml_printf (xml,
		       "<surface content='%s' width='%d' height='%d'>",
		       _content_to_string (recording_surface->content),
		       extents.width, extents.height);
    _cairo_xml_indent (xml, 2);

    cairo_surface_set_device_offset (surface, -extents.x, -extents.y);
    status = _cairo_recording_surface_replay (recording_surface, surface);
    cairo_surface_destroy (surface);

    _cairo_xml_indent (xml, -2);
    _cairo_xml_printf (xml, "</surface>");

    return status;
}
예제 #4
0
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;
}
static cairo_int_status_t
_paint_fallback_image (cairo_paginated_surface_t *surface,
		       cairo_rectangle_int_t     *rect)
{
    double x_scale = surface->base.x_fallback_resolution / surface->target->x_resolution;
    double y_scale = surface->base.y_fallback_resolution / surface->target->y_resolution;
    int x, y, width, height;
    cairo_status_t status;
    cairo_surface_t *image;
    cairo_surface_pattern_t pattern;
    cairo_clip_t *clip;

    x = rect->x;
    y = rect->y;
    width = rect->width;
    height = rect->height;
    image = _cairo_paginated_surface_create_image_surface (surface,
							   ceil (width  * x_scale),
							   ceil (height * y_scale));
    _cairo_surface_set_device_scale (image, x_scale, y_scale);
    /* set_device_offset just sets the x0/y0 components of the matrix;
     * so we have to do the scaling manually. */
    cairo_surface_set_device_offset (image, -x*x_scale, -y*y_scale);

    status = _cairo_recording_surface_replay (surface->recording_surface, image);
    if (unlikely (status))
	goto CLEANUP_IMAGE;

    _cairo_pattern_init_for_surface (&pattern, image);
    cairo_matrix_init (&pattern.base.matrix,
		       x_scale, 0, 0, y_scale, -x*x_scale, -y*y_scale);
    /* the fallback should be rendered at native resolution, so disable
     * filtering (if possible) to avoid introducing potential artifacts. */
    pattern.base.filter = CAIRO_FILTER_NEAREST;

    clip = _cairo_clip_intersect_rectangle (NULL, rect);
    status = _cairo_surface_paint (surface->target,
				   CAIRO_OPERATOR_SOURCE,
				   &pattern.base, clip);
    _cairo_clip_destroy (clip);
    _cairo_pattern_fini (&pattern.base);

CLEANUP_IMAGE:
    cairo_surface_destroy (image);

    return (cairo_int_status_t)status;
}
static cairo_status_t
_cairo_recording_surface_acquire_source_image (void			 *abstract_surface,
					       cairo_image_surface_t	**image_out,
					       void			**image_extra)
{
    cairo_status_t status;
    cairo_recording_surface_t *surface = abstract_surface;
    cairo_surface_t *image;

    image = _cairo_surface_has_snapshot (&surface->base,
					 &_cairo_image_surface_backend);
    if (image != NULL) {
	*image_out = (cairo_image_surface_t *) cairo_surface_reference (image);
	*image_extra = NULL;
	return CAIRO_STATUS_SUCCESS;
    }

    image = _cairo_image_surface_create_with_content (surface->content,
						      surface->extents.width,
						      surface->extents.height);
    if (unlikely (image->status))
	return image->status;

    cairo_surface_set_device_offset (image,
				     -surface->extents.x,
				     -surface->extents.y);

    status = _cairo_recording_surface_replay (&surface->base, image);
    if (unlikely (status)) {
	cairo_surface_destroy (image);
	return status;
    }

    _cairo_surface_attach_snapshot (&surface->base, image, NULL);

    *image_out = (cairo_image_surface_t *) image;
    *image_extra = NULL;
    return CAIRO_STATUS_SUCCESS;
}
/**
 * _cairo_recording_surface_snapshot
 * @surface: a #cairo_surface_t which must be a recording surface
 *
 * Make an immutable copy of @surface. It is an error to call a
 * surface-modifying function on the result of this function.
 *
 * The caller owns the return value and should call
 * cairo_surface_destroy() when finished with it. This function will not
 * return %NULL, but will return a nil surface instead.
 *
 * Return value: The snapshot surface.
 **/
static cairo_surface_t *
_cairo_recording_surface_snapshot (void *abstract_other)
{
    cairo_recording_surface_t *other = abstract_other;
    cairo_recording_surface_t *recording_surface;
    cairo_status_t status;

    recording_surface = malloc (sizeof (cairo_recording_surface_t));
    if (unlikely (recording_surface == NULL))
	return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));

    _cairo_surface_init (&recording_surface->base,
			 &cairo_recording_surface_backend,
			 NULL, /* device */
			 other->base.content);

    recording_surface->extents_pixels = other->extents_pixels;
    recording_surface->extents = other->extents;
    recording_surface->unbounded = other->unbounded;
    recording_surface->content = other->content;

    _cairo_clip_init_copy (&recording_surface->clip, &other->clip);

    /* XXX We should in theory be able to reuse the original array, but we
     * need to handle reference cycles during subsurface and self-copy.
     */
    recording_surface->replay_start_idx = 0;
    recording_surface->base.is_clear = TRUE;

    _cairo_array_init (&recording_surface->commands, sizeof (cairo_command_t *));
    status = _cairo_recording_surface_replay (&other->base, &recording_surface->base);
    if (unlikely (status)) {
	cairo_surface_destroy (&recording_surface->base);
	return _cairo_surface_create_in_error (status);
    }

    return &recording_surface->base;
}
예제 #8
0
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_matrix_t font_matrix_inverse;

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

    _cairo_type3_glyph_surface_set_stream (surface, stream);

    _cairo_scaled_font_freeze_cache (surface->scaled_font);
    status = _cairo_scaled_glyph_lookup (surface->scaled_font,
					 glyph_index,
					 CAIRO_SCALED_GLYPH_INFO_METRICS |
					 CAIRO_SCALED_GLYPH_INFO_RECORDING_SURFACE,
					 &scaled_glyph);
    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 == CAIRO_STATUS_SUCCESS)
	    status = CAIRO_INT_STATUS_IMAGE_FALLBACK;
    }
    if (_cairo_status_is_error (status)) {
	_cairo_scaled_font_thaw_cache (surface->scaled_font);
	return status;
    }

    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 mapped 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) {
	cairo_output_stream_t *mem_stream;

	mem_stream = _cairo_memory_stream_create ();
	status = mem_stream->status;
	if (unlikely (status))
	    goto FAIL;

	_cairo_type3_glyph_surface_set_stream (surface, mem_stream);

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

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

	_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 (status == CAIRO_STATUS_SUCCESS)
	    status = status2;
    }

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

  FAIL:
    _cairo_scaled_font_thaw_cache (surface->scaled_font);

    return status;
}