cairo_status_t
_cairo_recording_surface_get_bbox (cairo_recording_surface_t *surface,
				   cairo_box_t *bbox,
				   const cairo_matrix_t *transform)
{
    if (! surface->unbounded) {
	_cairo_box_from_rectangle (bbox, &surface->extents);
	if (transform != NULL)
	    _cairo_matrix_transform_bounding_box_fixed (transform, bbox, NULL);

	return CAIRO_STATUS_SUCCESS;
    }

    return _recording_surface_get_ink_bbox (surface, bbox, transform);
}
static cairo_int_status_t
_add_operation  (cairo_analysis_surface_t *surface,
		 cairo_rectangle_int_t    *rect,
		 cairo_int_status_t        backend_status)
{
    cairo_int_status_t status;
    cairo_box_t bbox;

    if (rect->width == 0 || rect->height == 0) {
	/* Even though the operation is not visible we must be careful
	 * to not allow unsupported operations to be replayed to the
	 * backend during CAIRO_PAGINATED_MODE_RENDER */
	if (backend_status == CAIRO_STATUS_SUCCESS ||
	    backend_status == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY)
	{
	    return CAIRO_STATUS_SUCCESS;
	}
	else
	{
	    return CAIRO_INT_STATUS_IMAGE_FALLBACK;
	}
    }

    _cairo_box_from_rectangle (&bbox, rect);

    if (surface->has_ctm) {

	_cairo_matrix_transform_bounding_box_fixed (&surface->ctm, &bbox, NULL);

	if (bbox.p1.x == bbox.p2.x || bbox.p1.y == bbox.p2.y) {
	    /* Even though the operation is not visible we must be
	     * careful to not allow unsupported operations to be
	     * replayed to the backend during
	     * CAIRO_PAGINATED_MODE_RENDER */
	    if (backend_status == CAIRO_STATUS_SUCCESS ||
		backend_status == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY)
	    {
		return CAIRO_STATUS_SUCCESS;
	    }
	    else
	    {
		return CAIRO_INT_STATUS_IMAGE_FALLBACK;
	    }
	}

	_cairo_box_round_to_rectangle (&bbox, rect);
    }

    if (surface->first_op) {
	surface->first_op = FALSE;
	surface->page_bbox = bbox;
    } else {
	if (bbox.p1.x < surface->page_bbox.p1.x)
	    surface->page_bbox.p1.x = bbox.p1.x;
	if (bbox.p1.y < surface->page_bbox.p1.y)
	    surface->page_bbox.p1.y = bbox.p1.y;
	if (bbox.p2.x > surface->page_bbox.p2.x)
	    surface->page_bbox.p2.x = bbox.p2.x;
	if (bbox.p2.y > surface->page_bbox.p2.y)
	    surface->page_bbox.p2.y = bbox.p2.y;
    }

    /* If the operation is completely enclosed within the fallback
     * region there is no benefit in emitting a native operation as
     * the fallback image will be painted on top.
     */
    if (_cairo_region_contains_rectangle (&surface->fallback_region, rect) == PIXMAN_REGION_IN)
	return CAIRO_INT_STATUS_IMAGE_FALLBACK;

    if (backend_status == CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY) {
	/* A status of CAIRO_INT_STATUS_FLATTEN_TRANSPARENCY indicates
	 * that the backend only supports this operation if the
	 * transparency removed. If the extents of this operation does
	 * not intersect any other native operation, the operation is
	 * natively supported and the backend will blend the
	 * transparency into the white background.
	 */
	if (_cairo_region_contains_rectangle (&surface->supported_region, rect) == PIXMAN_REGION_OUT)
	    backend_status = CAIRO_STATUS_SUCCESS;
    }

    if (backend_status == CAIRO_STATUS_SUCCESS) {
	/* Add the operation to the supported region. Operations in
	 * this region will be emitted as native operations.
	 */
	surface->has_supported = TRUE;
	status = _cairo_region_union_rect (&surface->supported_region,
					   &surface->supported_region,
					   rect);
	return status;
    }

    /* Add the operation to the unsupported region. This region will
     * be painted as an image after all native operations have been
     * emitted.
     */
    surface->has_unsupported = TRUE;
    status = _cairo_region_union_rect (&surface->fallback_region,
				       &surface->fallback_region,
				       rect);

    /* The status CAIRO_INT_STATUS_IMAGE_FALLBACK is used to indicate
     * unsupported operations to the meta surface as using
     * CAIRO_INT_STATUS_UNSUPPORTED would cause cairo-surface to
     * invoke the cairo-surface-fallback path then return
     * CAIRO_STATUS_SUCCESS.
     */
    if (status == CAIRO_STATUS_SUCCESS)
	return CAIRO_INT_STATUS_IMAGE_FALLBACK;
    else
	return status;
}
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;
}
Beispiel #4
0
static cairo_int_status_t
_analyze_recording_surface_pattern (cairo_analysis_surface_t *surface,
				    const cairo_pattern_t    *pattern,
				    cairo_rectangle_int_t    *extents)
{
    const cairo_surface_pattern_t *surface_pattern;
    cairo_analysis_surface_t *tmp;
    cairo_surface_t *source, *proxy;
    cairo_matrix_t p2d;
    cairo_int_status_t status, analysis_status;
    cairo_bool_t surface_is_unbounded;
    cairo_bool_t unused;

    assert (pattern->type == CAIRO_PATTERN_TYPE_SURFACE);
    surface_pattern = (const cairo_surface_pattern_t *) pattern;
    assert (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING);
    source = surface_pattern->surface;

    proxy = _cairo_surface_has_snapshot (source, &proxy_backend);
    if (proxy != NULL) {
	/* nothing untoward found so far */
	return CAIRO_STATUS_SUCCESS;
    }

    tmp = (cairo_analysis_surface_t *)
	_cairo_analysis_surface_create (surface->target);
    if (unlikely (tmp->base.status)) {
	status =tmp->base.status;
	goto cleanup1;
    }
    proxy = attach_proxy (source, &tmp->base);

    p2d = pattern->matrix;
    status = cairo_matrix_invert (&p2d);
    assert (status == CAIRO_INT_STATUS_SUCCESS);
    _cairo_analysis_surface_set_ctm (&tmp->base, &p2d);


    source = _cairo_surface_get_source (source, NULL);
    surface_is_unbounded = (pattern->extend == CAIRO_EXTEND_REPEAT
				     || pattern->extend == CAIRO_EXTEND_REFLECT);
    status = _cairo_recording_surface_replay_and_create_regions (source,
								 &pattern->matrix,
								 &tmp->base,
								 surface_is_unbounded);
    if (unlikely (status))
	goto cleanup2;

    /* black background or mime data fills entire extents */
    if (!(source->content & CAIRO_CONTENT_ALPHA) || _cairo_surface_has_mime_image (source)) {
	cairo_rectangle_int_t rect;

	if (_cairo_surface_get_extents (source, &rect)) {
	    cairo_box_t bbox;

	    _cairo_box_from_rectangle (&bbox, &rect);
	    _cairo_matrix_transform_bounding_box_fixed (&p2d, &bbox, NULL);
	    _cairo_box_round_to_rectangle (&bbox, &rect);
	    status = _add_operation (tmp, &rect, CAIRO_INT_STATUS_SUCCESS);
	    if (status == CAIRO_INT_STATUS_IMAGE_FALLBACK)
		status = CAIRO_INT_STATUS_SUCCESS;
	    if (unlikely (status))
		goto cleanup2;
	}
    }

    if (tmp->has_supported) {
	surface->has_supported = TRUE;
	unused = cairo_region_union (&surface->supported_region, &tmp->supported_region);
    }

    if (tmp->has_unsupported) {
	surface->has_unsupported = TRUE;
	unused = cairo_region_union (&surface->fallback_region, &tmp->fallback_region);
    }

    analysis_status = tmp->has_unsupported ? CAIRO_INT_STATUS_IMAGE_FALLBACK : CAIRO_INT_STATUS_SUCCESS;
    if (pattern->extend != CAIRO_EXTEND_NONE) {
	_cairo_unbounded_rectangle_init (extents);
    } else {
	status = cairo_matrix_invert (&tmp->ctm);
	_cairo_matrix_transform_bounding_box_fixed (&tmp->ctm,
						    &tmp->page_bbox, NULL);
	_cairo_box_round_to_rectangle (&tmp->page_bbox, extents);
    }

  cleanup2:
    detach_proxy (proxy);
  cleanup1:
    cairo_surface_destroy (&tmp->base);

    if (unlikely (status))
	return status;

    return analysis_status;
}