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; }
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; }