diff options
Diffstat (limited to 'src/cairo-paginated-surface.c')
-rw-r--r-- | src/cairo-paginated-surface.c | 234 |
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 */ |