summaryrefslogtreecommitdiff
path: root/src/cairo-paginated-surface.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cairo-paginated-surface.c')
-rw-r--r--src/cairo-paginated-surface.c234
1 files changed, 97 insertions, 137 deletions
diff --git a/src/cairo-paginated-surface.c b/src/cairo-paginated-surface.c
index 033df35a..23443a5d 100644
--- a/src/cairo-paginated-surface.c
+++ b/src/cairo-paginated-surface.c
@@ -60,17 +60,36 @@ _cairo_paginated_surface_create_similar (void *abstract_surface,
int width,
int height)
{
- cairo_paginated_surface_t *surface = abstract_surface;
- return cairo_surface_create_similar (surface->target, content,
- width, height);
+ cairo_rectangle_t rect;
+ rect.x = rect.y = 0.;
+ rect.width = width;
+ rect.height = height;
+ return cairo_meta_surface_create (content, &rect);
+}
+
+static cairo_surface_t *
+_create_meta_surface_for_target (cairo_surface_t *target,
+ cairo_content_t content)
+{
+ cairo_rectangle_int_t rect;
+
+ if (_cairo_surface_get_extents (target, &rect)) {
+ cairo_rectangle_t meta_extents;
+
+ meta_extents.x = rect.x;
+ meta_extents.y = rect.y;
+ meta_extents.width = rect.width;
+ meta_extents.height = rect.height;
+
+ return cairo_meta_surface_create (content, &meta_extents);
+ } else {
+ return cairo_meta_surface_create (content, NULL);
+ }
}
-/* XXX The integer width,height here should be doubles and all uses updated */
cairo_surface_t *
_cairo_paginated_surface_create (cairo_surface_t *target,
cairo_content_t content,
- int width,
- int height,
const cairo_paginated_surface_backend_t *backend)
{
cairo_paginated_surface_t *surface;
@@ -87,18 +106,15 @@ _cairo_paginated_surface_create (cairo_surface_t *target,
/* Override surface->base.type with target's type so we don't leak
* evidence of the paginated wrapper out to the user. */
- surface->base.type = cairo_surface_get_type (target);
+ surface->base.type = target->type;
surface->target = cairo_surface_reference (target);
surface->content = content;
- surface->width = width;
- surface->height = height;
-
surface->backend = backend;
- surface->meta = cairo_meta_surface_create (content, width, height);
- status = cairo_surface_status (surface->meta);
+ surface->meta = _create_meta_surface_for_target (target, content);
+ status = surface->meta->status;
if (unlikely (status))
goto FAIL_CLEANUP_SURFACE;
@@ -132,31 +148,6 @@ _cairo_paginated_surface_get_target (cairo_surface_t *surface)
return paginated_surface->target;
}
-cairo_status_t
-_cairo_paginated_surface_set_size (cairo_surface_t *surface,
- int width,
- int height)
-{
- cairo_paginated_surface_t *paginated_surface;
- cairo_status_t status;
-
- assert (_cairo_surface_is_paginated (surface));
-
- paginated_surface = (cairo_paginated_surface_t *) surface;
-
- paginated_surface->width = width;
- paginated_surface->height = height;
-
- cairo_surface_destroy (paginated_surface->meta);
- paginated_surface->meta = cairo_meta_surface_create (paginated_surface->content,
- width, height);
- status = cairo_surface_status (paginated_surface->meta);
- if (unlikely (status))
- return _cairo_surface_set_error (surface, status);
-
- return CAIRO_STATUS_SUCCESS;
-}
-
static cairo_status_t
_cairo_paginated_surface_finish (void *abstract_surface)
{
@@ -168,18 +159,11 @@ _cairo_paginated_surface_finish (void *abstract_surface)
status = cairo_surface_status (abstract_surface);
}
- if (status == CAIRO_STATUS_SUCCESS) {
- cairo_surface_finish (surface->target);
- status = cairo_surface_status (surface->target);
- }
-
- if (status == CAIRO_STATUS_SUCCESS) {
- cairo_surface_finish (surface->meta);
- status = cairo_surface_status (surface->meta);
- }
-
cairo_surface_destroy (surface->target);
+ cairo_surface_finish (surface->meta);
+ if (status == CAIRO_STATUS_SUCCESS)
+ status = cairo_surface_status (surface->meta);
cairo_surface_destroy (surface->meta);
return status;
@@ -210,13 +194,14 @@ _cairo_paginated_surface_acquire_source_image (void *abstract_surface,
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;
- status = _cairo_surface_get_extents (surface->target, &extents);
- if (unlikely (status))
- return status;
+ is_bounded = _cairo_surface_get_extents (surface->target, &extents);
+ if (! is_bounded)
+ return CAIRO_INT_STATUS_UNSUPPORTED;
image = _cairo_paginated_surface_create_image_surface (surface,
extents.width,
@@ -248,11 +233,11 @@ _paint_fallback_image (cairo_paginated_surface_t *surface,
{
double x_scale = surface->base.x_fallback_resolution / surface->target->x_resolution;
double y_scale = surface->base.y_fallback_resolution / surface->target->y_resolution;
- cairo_matrix_t matrix;
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;
@@ -271,15 +256,21 @@ _paint_fallback_image (cairo_paginated_surface_t *surface,
goto CLEANUP_IMAGE;
_cairo_pattern_init_for_surface (&pattern, image);
- cairo_matrix_init (&matrix, x_scale, 0, 0, y_scale, -x*x_scale, -y*y_scale);
- cairo_pattern_set_matrix (&pattern.base, &matrix);
+ 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;
+ status = _cairo_clip_init_rectangle (&clip, rect);
+ if (unlikely (status))
+ goto CLEANUP_IMAGE;
+
status = _cairo_surface_paint (surface->target,
CAIRO_OPERATOR_SOURCE,
- &pattern.base, NULL);
+ &pattern.base, &clip);
+
+ _cairo_clip_reset (&clip);
_cairo_pattern_fini (&pattern.base);
CLEANUP_IMAGE:
@@ -295,12 +286,11 @@ _paint_page (cairo_paginated_surface_t *surface)
cairo_status_t status;
cairo_bool_t has_supported, has_page_fallback, has_finegrained_fallback;
- if (surface->target->status)
+ if (unlikely (surface->target->status))
return surface->target->status;
- analysis = _cairo_analysis_surface_create (surface->target,
- surface->width, surface->height);
- if (analysis->status)
+ analysis = _cairo_analysis_surface_create (surface->target);
+ if (unlikely (analysis->status))
return _cairo_surface_set_error (surface->target, analysis->status);
surface->backend->set_paginated_mode (surface->target,
@@ -365,16 +355,19 @@ _paint_page (cairo_paginated_surface_t *surface)
}
if (has_page_fallback) {
- cairo_rectangle_int_t rect;
+ cairo_rectangle_int_t extents;
+ cairo_bool_t is_bounded;
surface->backend->set_paginated_mode (surface->target,
CAIRO_PAGINATED_MODE_FALLBACK);
- rect.x = 0;
- rect.y = 0;
- rect.width = surface->width;
- rect.height = surface->height;
- status = _paint_fallback_image (surface, &rect);
+ is_bounded = _cairo_surface_get_extents (surface->target, &extents);
+ if (! is_bounded) {
+ status = CAIRO_INT_STATUS_UNSUPPORTED;
+ goto FAIL;
+ }
+
+ status = _paint_fallback_image (surface, &extents);
if (unlikely (status))
goto FAIL;
}
@@ -386,15 +379,6 @@ _paint_page (cairo_paginated_surface_t *surface)
surface->backend->set_paginated_mode (surface->target,
CAIRO_PAGINATED_MODE_FALLBACK);
- /* Reset clip region before drawing the fall back images */
- status = _cairo_surface_intersect_clip_path (surface->target,
- NULL,
- CAIRO_FILL_RULE_WINDING,
- CAIRO_GSTATE_TOLERANCE_DEFAULT,
- CAIRO_ANTIALIAS_DEFAULT);
- if (unlikely (status))
- goto FAIL;
-
region = _cairo_analysis_surface_get_unsupported (analysis);
num_rects = cairo_region_num_rectangles (region);
@@ -402,9 +386,7 @@ _paint_page (cairo_paginated_surface_t *surface)
cairo_rectangle_int_t rect;
cairo_region_get_rectangle (region, i, &rect);
-
status = _paint_fallback_image (surface, &rect);
-
if (unlikely (status))
goto FAIL;
}
@@ -445,7 +427,7 @@ _cairo_paginated_surface_copy_page (void *abstract_surface)
surface->page_num++;
- /* XXX: It might make sense to add some suport here for calling
+ /* XXX: It might make sense to add some support here for calling
* cairo_surface_copy_page on the target surface. It would be an
* optimization for the output, but the interaction with image
* fallbacks gets tricky. For now, we just let the target see a
@@ -471,20 +453,19 @@ _cairo_paginated_surface_show_page (void *abstract_surface)
return status;
cairo_surface_show_page (surface->target);
- status = cairo_surface_status (surface->target);
+ status = surface->target->status;
if (unlikely (status))
return status;
- status = cairo_surface_status (surface->meta);
+ status = surface->meta->status;
if (unlikely (status))
return status;
cairo_surface_destroy (surface->meta);
- surface->meta = cairo_meta_surface_create (surface->content,
- surface->width,
- surface->height);
- status = cairo_surface_status (surface->meta);
+ surface->meta = _create_meta_surface_for_target (surface->target,
+ surface->content);
+ status = surface->meta->status;
if (unlikely (status))
return status;
@@ -494,21 +475,7 @@ _cairo_paginated_surface_show_page (void *abstract_surface)
return CAIRO_STATUS_SUCCESS;
}
-static cairo_int_status_t
-_cairo_paginated_surface_intersect_clip_path (void *abstract_surface,
- cairo_path_fixed_t *path,
- cairo_fill_rule_t fill_rule,
- double tolerance,
- cairo_antialias_t antialias)
-{
- cairo_paginated_surface_t *surface = abstract_surface;
-
- return _cairo_surface_intersect_clip_path (surface->meta,
- path, fill_rule,
- tolerance, antialias);
-}
-
-static cairo_int_status_t
+static cairo_bool_t
_cairo_paginated_surface_get_extents (void *abstract_surface,
cairo_rectangle_int_t *rectangle)
{
@@ -530,7 +497,7 @@ static cairo_int_status_t
_cairo_paginated_surface_paint (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
cairo_paginated_surface_t *surface = abstract_surface;
@@ -540,7 +507,7 @@ _cairo_paginated_surface_paint (void *abstract_surface,
surface->page_is_blank = FALSE;
- return _cairo_surface_paint (surface->meta, op, source, NULL);
+ return _cairo_surface_paint (surface->meta, op, source, clip);
}
static cairo_int_status_t
@@ -548,11 +515,17 @@ _cairo_paginated_surface_mask (void *abstract_surface,
cairo_operator_t op,
const cairo_pattern_t *source,
const cairo_pattern_t *mask,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
cairo_paginated_surface_t *surface = abstract_surface;
- return _cairo_surface_mask (surface->meta, op, source, mask, NULL);
+ /* Optimize away erasing of nothing. */
+ if (surface->page_is_blank && op == CAIRO_OPERATOR_CLEAR)
+ return CAIRO_STATUS_SUCCESS;
+
+ surface->page_is_blank = FALSE;
+
+ return _cairo_surface_mask (surface->meta, op, source, mask, clip);
}
static cairo_int_status_t
@@ -565,7 +538,7 @@ _cairo_paginated_surface_stroke (void *abstract_surface,
cairo_matrix_t *ctm_inverse,
double tolerance,
cairo_antialias_t antialias,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
cairo_paginated_surface_t *surface = abstract_surface;
@@ -578,7 +551,8 @@ _cairo_paginated_surface_stroke (void *abstract_surface,
return _cairo_surface_stroke (surface->meta, op, source,
path, style,
ctm, ctm_inverse,
- tolerance, antialias, NULL);
+ tolerance, antialias,
+ clip);
}
static cairo_int_status_t
@@ -589,7 +563,7 @@ _cairo_paginated_surface_fill (void *abstract_surface,
cairo_fill_rule_t fill_rule,
double tolerance,
cairo_antialias_t antialias,
- cairo_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
cairo_paginated_surface_t *surface = abstract_surface;
@@ -601,7 +575,8 @@ _cairo_paginated_surface_fill (void *abstract_surface,
return _cairo_surface_fill (surface->meta, op, source,
path, fill_rule,
- tolerance, antialias, NULL);
+ tolerance, antialias,
+ clip);
}
static cairo_bool_t
@@ -614,20 +589,19 @@ _cairo_paginated_surface_has_show_text_glyphs (void *abstract_surface)
static cairo_int_status_t
_cairo_paginated_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_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_rectangle_int_t *extents)
+ cairo_clip_t *clip)
{
cairo_paginated_surface_t *surface = abstract_surface;
- cairo_int_status_t status;
/* Optimize away erasing of nothing. */
if (surface->page_is_blank && op == CAIRO_OPERATOR_CLEAR)
@@ -635,24 +609,13 @@ _cairo_paginated_surface_show_text_glyphs (void *abstract_surface,
surface->page_is_blank = FALSE;
- /* Since this is a "wrapping" surface, we're calling back into
- * _cairo_surface_show_text_glyphs from within a call to the same.
- * Since _cairo_surface_show_text_glyphs acquires a mutex, we release
- * and re-acquire the mutex around this nested call.
- *
- * Yes, this is ugly, but we consider it pragmatic as compared to
- * adding locking code to all 18 surface-backend-specific
- * show_glyphs functions, (which would get less testing and likely
- * lead to bugs).
- */
- status = _cairo_surface_show_text_glyphs (surface->meta, op, source,
- utf8, utf8_len,
- glyphs, num_glyphs,
- clusters, num_clusters,
- cluster_flags,
- scaled_font, NULL);
-
- return status;
+ return _cairo_surface_show_text_glyphs (surface->meta, op, source,
+ utf8, utf8_len,
+ glyphs, num_glyphs,
+ clusters, num_clusters,
+ cluster_flags,
+ scaled_font,
+ clip);
}
static cairo_surface_t *
@@ -679,8 +642,6 @@ static const cairo_surface_backend_t cairo_paginated_surface_backend = {
NULL, /* check_span_renderer */
_cairo_paginated_surface_copy_page,
_cairo_paginated_surface_show_page,
- NULL, /* set_clip_region */
- _cairo_paginated_surface_intersect_clip_path,
_cairo_paginated_surface_get_extents,
NULL, /* old_show_glyphs */
_cairo_paginated_surface_get_font_options,
@@ -695,7 +656,6 @@ static const cairo_surface_backend_t cairo_paginated_surface_backend = {
NULL, /* show_glyphs */
_cairo_paginated_surface_snapshot,
NULL, /* is_similar */
- NULL, /* reset */
NULL, /* fill_stroke */
NULL, /* create_solid_pattern_surface */
NULL, /* can_repaint_solid_pattern_surface */