summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Wilson <chris@chris-wilson.co.uk>2009-09-01 18:24:42 +0100
committerChris Wilson <chris@chris-wilson.co.uk>2009-09-01 18:24:42 +0100
commit665f5829541703b29e33f80bebf579a17f47a892 (patch)
tree97448ca1c817138011d186ee056292793659be9c
parentc4c7db96750337076b953a4938afc7b5f16815fc (diff)
[ps/pdf] Trim patterns to operation extents
If we have to rasterise a pattern for use by PS/PDF (for example, to satisfy CAIRO_EXTENT_PAD) then only generate an image large enough to cover the operation extents. We ensure tight coverage by computing the extents afresh - we could do this lazily in the future, but we can not rely on the bounds as computed by the analysis surface as for native operations they may not be tight.
-rw-r--r--src/cairo-pdf-surface.c67
-rw-r--r--src/cairo-ps-surface.c76
-rw-r--r--src/cairo-surface.c162
-rw-r--r--src/cairoint.h49
4 files changed, 319 insertions, 35 deletions
diff --git a/src/cairo-pdf-surface.c b/src/cairo-pdf-surface.c
index 76016872..ac78f589 100644
--- a/src/cairo-pdf-surface.c
+++ b/src/cairo-pdf-surface.c
@@ -1162,7 +1162,7 @@ _cairo_pdf_surface_add_source_surface (cairo_pdf_surface_t *surface,
static cairo_status_t
_cairo_pdf_surface_add_pdf_pattern (cairo_pdf_surface_t *surface,
const cairo_pattern_t *pattern,
- cairo_clip_t *clip,
+ const cairo_rectangle_int_t *extents,
cairo_pdf_resource_t *pattern_res,
cairo_pdf_resource_t *gstate_res)
{
@@ -1221,8 +1221,8 @@ _cairo_pdf_surface_add_pdf_pattern (cairo_pdf_surface_t *surface,
pdf_pattern.width = surface->width;
pdf_pattern.height = surface->height;
- if (clip != NULL) {
- pdf_pattern.extents = clip->path->extents;
+ if (extents != NULL) {
+ pdf_pattern.extents = *extents;
} else {
pdf_pattern.extents.x = 0;
pdf_pattern.extents.y = 0;
@@ -5315,6 +5315,7 @@ _cairo_pdf_surface_paint (void *abstract_surface,
cairo_status_t status;
cairo_pdf_smask_group_t *group;
cairo_pdf_resource_t pattern_res, gstate_res;
+ cairo_rectangle_int_t extents;
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
return _cairo_pdf_surface_analyze_operation (surface, op, source);
@@ -5347,9 +5348,15 @@ _cairo_pdf_surface_paint (void *abstract_surface,
return _cairo_output_stream_get_status (surface->output);
}
+ status = _cairo_surface_paint_extents (&surface->base,
+ op, source, clip,
+ &extents);
+ if (unlikely (status))
+ return status;
+
pattern_res.id = 0;
gstate_res.id = 0;
- status = _cairo_pdf_surface_add_pdf_pattern (surface, source, clip,
+ status = _cairo_pdf_surface_add_pdf_pattern (surface, source, &extents,
&pattern_res, &gstate_res);
if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO))
return CAIRO_STATUS_SUCCESS;
@@ -5512,6 +5519,7 @@ _cairo_pdf_surface_stroke (void *abstract_surface,
cairo_status_t status;
cairo_pdf_smask_group_t *group;
cairo_pdf_resource_t pattern_res, gstate_res;
+ cairo_rectangle_int_t extents;
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
return _cairo_pdf_surface_analyze_operation (surface, op, source);
@@ -5522,9 +5530,17 @@ _cairo_pdf_surface_stroke (void *abstract_surface,
if (unlikely (status))
return status;
+ status = _cairo_surface_stroke_extents (&surface->base,
+ op, source, path,
+ style, ctm, ctm_inverse,
+ tolerance, antialias,
+ clip, &extents);
+ if (unlikely (status))
+ return status;
+
pattern_res.id = 0;
gstate_res.id = 0;
- status = _cairo_pdf_surface_add_pdf_pattern (surface, source, clip,
+ status = _cairo_pdf_surface_add_pdf_pattern (surface, source, &extents,
&pattern_res, &gstate_res);
if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO))
return CAIRO_STATUS_SUCCESS;
@@ -5613,6 +5629,7 @@ _cairo_pdf_surface_fill (void *abstract_surface,
cairo_status_t status;
cairo_pdf_smask_group_t *group;
cairo_pdf_resource_t pattern_res, gstate_res;
+ cairo_rectangle_int_t extents;
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE) {
return _cairo_pdf_surface_analyze_operation (surface, op, source);
@@ -5651,9 +5668,16 @@ _cairo_pdf_surface_fill (void *abstract_surface,
return _cairo_output_stream_get_status (surface->output);
}
+ status = _cairo_surface_fill_extents (&surface->base,
+ op, source, path, fill_rule,
+ tolerance, antialias,
+ clip, &extents);
+ if (unlikely (status))
+ return status;
+
pattern_res.id = 0;
gstate_res.id = 0;
- status = _cairo_pdf_surface_add_pdf_pattern (surface, source, clip,
+ status = _cairo_pdf_surface_add_pdf_pattern (surface, source, &extents,
&pattern_res, &gstate_res);
if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO))
return CAIRO_STATUS_SUCCESS;
@@ -5740,6 +5764,7 @@ _cairo_pdf_surface_fill_stroke (void *abstract_surface,
cairo_pdf_surface_t *surface = abstract_surface;
cairo_status_t status;
cairo_pdf_resource_t fill_pattern_res, stroke_pattern_res, gstate_res;
+ cairo_rectangle_int_t extents;
/* During analysis we return unsupported and let the _fill and
* _stroke functions that are on the fallback path do the analysis
@@ -5771,10 +5796,18 @@ _cairo_pdf_surface_fill_stroke (void *abstract_surface,
if (unlikely (status))
return status;
+ status = _cairo_surface_fill_extents (&surface->base,
+ fill_op, fill_source, path, fill_rule,
+ fill_tolerance, fill_antialias,
+ clip, &extents);
+ if (unlikely (status))
+ return status;
+
+
fill_pattern_res.id = 0;
gstate_res.id = 0;
status = _cairo_pdf_surface_add_pdf_pattern (surface, fill_source,
- clip,
+ &extents,
&fill_pattern_res,
&gstate_res);
if (unlikely (status))
@@ -5782,11 +5815,19 @@ _cairo_pdf_surface_fill_stroke (void *abstract_surface,
assert (gstate_res.id == 0);
+ status = _cairo_surface_stroke_extents (&surface->base,
+ stroke_op, stroke_source, path,
+ stroke_style, stroke_ctm, stroke_ctm_inverse,
+ stroke_tolerance, stroke_antialias,
+ clip, &extents);
+ if (unlikely (status))
+ return status;
+
stroke_pattern_res.id = 0;
gstate_res.id = 0;
status = _cairo_pdf_surface_add_pdf_pattern (surface,
stroke_source,
- clip,
+ &extents,
&stroke_pattern_res,
&gstate_res);
if (unlikely (status))
@@ -5846,6 +5887,7 @@ _cairo_pdf_surface_show_text_glyphs (void *abstract_surface,
cairo_status_t status;
cairo_pdf_smask_group_t *group;
cairo_pdf_resource_t pattern_res, gstate_res;
+ cairo_rectangle_int_t extents;
if (surface->paginated_mode == CAIRO_PAGINATED_MODE_ANALYZE)
return _cairo_pdf_surface_analyze_operation (surface, op, source);
@@ -5856,9 +5898,16 @@ _cairo_pdf_surface_show_text_glyphs (void *abstract_surface,
if (unlikely (status))
return status;
+ status = _cairo_surface_glyphs_extents (&surface->base, op, source,
+ glyphs, num_glyphs,
+ scaled_font,
+ clip, &extents);
+ if (unlikely (status))
+ return status;
+
pattern_res.id = 0;
gstate_res.id = 0;
- status = _cairo_pdf_surface_add_pdf_pattern (surface, source, clip,
+ status = _cairo_pdf_surface_add_pdf_pattern (surface, source, &extents,
&pattern_res, &gstate_res);
if (unlikely (status == CAIRO_INT_STATUS_NOTHING_TO_DO))
return CAIRO_STATUS_SUCCESS;
diff --git a/src/cairo-ps-surface.c b/src/cairo-ps-surface.c
index 6f1bcfcf..49d962ba 100644
--- a/src/cairo-ps-surface.c
+++ b/src/cairo-ps-surface.c
@@ -2277,12 +2277,14 @@ _cairo_ps_surface_emit_meta_surface (cairo_ps_surface_t *surface,
double old_width, old_height;
cairo_matrix_t old_cairo_to_ps;
cairo_content_t old_content;
+ cairo_rectangle_int_t old_page_bbox;
cairo_box_t bbox;
cairo_status_t status;
old_content = surface->content;
old_width = surface->width;
old_height = surface->height;
+ old_page_bbox = surface->page_bbox;
old_cairo_to_ps = surface->cairo_to_ps;
status =
@@ -2292,9 +2294,18 @@ _cairo_ps_surface_emit_meta_surface (cairo_ps_surface_t *surface,
if (unlikely (status))
return status;
- /* XXX is this still necessary? */
+#if DEBUG_PS
+ _cairo_output_stream_printf (surface->stream,
+ "%% _cairo_ps_surface_emit_meta_surface (%f, %f), (%f, %f)\n",
+ _cairo_fixed_to_double (bbox.p1.x),
+ _cairo_fixed_to_double (bbox.p1.y),
+ _cairo_fixed_to_double (bbox.p2.x),
+ _cairo_fixed_to_double (bbox.p2.y));
+#endif
+
surface->width = _cairo_fixed_to_double (bbox.p2.x - bbox.p1.x);
surface->height = _cairo_fixed_to_double (bbox.p2.y - bbox.p1.y);
+ _cairo_box_round_to_rectangle (&bbox, &surface->page_bbox);
surface->current_pattern_is_solid_color = FALSE;
_cairo_pdf_operators_reset (&surface->pdf_operators);
@@ -2325,6 +2336,7 @@ _cairo_ps_surface_emit_meta_surface (cairo_ps_surface_t *surface,
surface->content = old_content;
surface->width = old_width;
surface->height = old_height;
+ surface->page_bbox = old_page_bbox;
surface->current_pattern_is_solid_color = FALSE;
_cairo_pdf_operators_reset (&surface->pdf_operators);
surface->cairo_to_ps = old_cairo_to_ps;
@@ -3235,21 +3247,6 @@ _cairo_ps_surface_get_font_options (void *abstract_surface,
cairo_font_options_set_antialias (options, CAIRO_ANTIALIAS_GRAY);
}
-static cairo_bool_t
-_rectangle_intersect_clip (cairo_rectangle_int_t *extents, cairo_clip_t *clip)
-{
- const cairo_rectangle_int_t *clip_extents;
-
- clip_extents = NULL;
- if (clip != NULL)
- clip_extents = _cairo_clip_get_extents (clip);
-
- if (clip_extents != NULL)
- return _cairo_rectangle_intersect (extents, clip_extents);
-
- return TRUE;
-}
-
static cairo_int_status_t
_cairo_ps_surface_paint (void *abstract_surface,
cairo_operator_t op,
@@ -3271,8 +3268,13 @@ _cairo_ps_surface_paint (void *abstract_surface,
"%% _cairo_ps_surface_paint\n");
#endif
- extents = surface->page_bbox;
- if (! _rectangle_intersect_clip (&extents, clip))
+ status = _cairo_surface_paint_extents (&surface->base,
+ op, source, clip,
+ &extents);
+ if (unlikely (status))
+ return status;
+
+ if (! _cairo_rectangle_intersect (&extents, &surface->page_bbox))
return CAIRO_STATUS_SUCCESS;
status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
@@ -3333,8 +3335,16 @@ _cairo_ps_surface_stroke (void *abstract_surface,
"%% _cairo_ps_surface_stroke\n");
#endif
- extents = surface->page_bbox;
- if (! _rectangle_intersect_clip (&extents, clip))
+ status = _cairo_surface_stroke_extents (&surface->base,
+ op, source,
+ path, style,
+ ctm, ctm_inverse,
+ tolerance, antialias,
+ clip, &extents);
+ if (unlikely (status))
+ return status;
+
+ if (! _cairo_rectangle_intersect (&extents, &surface->page_bbox))
return CAIRO_STATUS_SUCCESS;
status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
@@ -3379,14 +3389,21 @@ _cairo_ps_surface_fill (void *abstract_surface,
"%% _cairo_ps_surface_fill\n");
#endif
- extents = surface->page_bbox;
- if (! _rectangle_intersect_clip (&extents, clip))
- return CAIRO_STATUS_SUCCESS;
-
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (unlikely (status))
return status;
+ status = _cairo_surface_fill_extents (&surface->base,
+ op, source,
+ path, fill_rule,
+ tolerance, antialias,
+ clip, &extents);
+ if (unlikely (status))
+ return status;
+
+ if (! _cairo_rectangle_intersect (&extents, &surface->page_bbox))
+ return CAIRO_STATUS_SUCCESS;
+
status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
if (unlikely (status))
return status;
@@ -3454,8 +3471,15 @@ _cairo_ps_surface_show_glyphs (void *abstract_surface,
if (num_glyphs <= 0)
return CAIRO_STATUS_SUCCESS;
- extents = surface->page_bbox;
- if (! _rectangle_intersect_clip (&extents, clip))
+ status = _cairo_surface_glyphs_extents (&surface->base,
+ op, source,
+ glyphs, num_glyphs,
+ scaled_font,
+ clip, &extents);
+ if (unlikely (status))
+ return status;
+
+ if (! _cairo_rectangle_intersect (&extents, &surface->page_bbox))
return CAIRO_STATUS_SUCCESS;
status = _cairo_surface_clipper_set_clip (&surface->clipper, clip);
diff --git a/src/cairo-surface.c b/src/cairo-surface.c
index 46abf25c..6dab8e22 100644
--- a/src/cairo-surface.c
+++ b/src/cairo-surface.c
@@ -2841,6 +2841,168 @@ _cairo_surface_set_resolution (cairo_surface_t *surface,
surface->y_resolution = y_res;
}
+/* Generic methods for determining operation extents. */
+
+static void
+_rectangle_intersect_clip (cairo_rectangle_int_t *extents, cairo_clip_t *clip)
+{
+ const cairo_rectangle_int_t *clip_extents;
+ cairo_bool_t is_empty;
+
+ clip_extents = NULL;
+ if (clip != NULL)
+ clip_extents = _cairo_clip_get_extents (clip);
+
+ if (clip_extents != NULL)
+ is_empty = _cairo_rectangle_intersect (extents, clip_extents);
+}
+
+static void
+_cairo_surface_operation_extents (cairo_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_clip_t *clip,
+ cairo_rectangle_int_t *extents)
+{
+ cairo_bool_t is_empty;
+
+ is_empty = _cairo_surface_get_extents (surface, extents);
+
+ if (_cairo_operator_bounded_by_source (op)) {
+ cairo_rectangle_int_t source_extents;
+
+ _cairo_pattern_get_extents (source, &source_extents);
+ is_empty = _cairo_rectangle_intersect (extents, &source_extents);
+ }
+
+ _rectangle_intersect_clip (extents, clip);
+}
+
+cairo_status_t
+_cairo_surface_paint_extents (cairo_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_clip_t *clip,
+ cairo_rectangle_int_t *extents)
+{
+ _cairo_surface_operation_extents (surface, op, source, clip, extents);
+ return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_status_t
+_cairo_surface_mask_extents (cairo_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_pattern_t *mask,
+ cairo_clip_t *clip,
+ cairo_rectangle_int_t *extents)
+{
+ cairo_bool_t is_empty;
+
+ _cairo_surface_operation_extents (surface, op, source, clip, extents);
+
+ if (_cairo_operator_bounded_by_mask (op)) {
+ cairo_rectangle_int_t mask_extents;
+
+ _cairo_pattern_get_extents (mask, &mask_extents);
+ is_empty = _cairo_rectangle_intersect (extents, &mask_extents);
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_status_t
+_cairo_surface_stroke_extents (cairo_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_path_fixed_t *path,
+ cairo_stroke_style_t *style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip,
+ cairo_rectangle_int_t *extents)
+{
+ cairo_status_t status;
+ cairo_bool_t is_empty;
+
+ _cairo_surface_operation_extents (surface, op, source, clip, extents);
+
+ if (_cairo_operator_bounded_by_mask (op)) {
+ cairo_rectangle_int_t mask_extents;
+
+ status = _cairo_path_fixed_stroke_extents (path, style,
+ ctm, ctm_inverse,
+ tolerance,
+ &mask_extents);
+ if (unlikely (status))
+ return status;
+
+ is_empty = _cairo_rectangle_intersect (extents, &mask_extents);
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_status_t
+_cairo_surface_fill_extents (cairo_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip,
+ cairo_rectangle_int_t *extents)
+{
+ cairo_bool_t is_empty;
+
+ _cairo_surface_operation_extents (surface, op, source, clip, extents);
+
+ if (_cairo_operator_bounded_by_mask (op)) {
+ cairo_rectangle_int_t mask_extents;
+
+ _cairo_path_fixed_fill_extents (path, fill_rule, tolerance,
+ &mask_extents);
+ is_empty = _cairo_rectangle_intersect (extents, &mask_extents);
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
+cairo_status_t
+_cairo_surface_glyphs_extents (cairo_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_scaled_font_t *scaled_font,
+ cairo_clip_t *clip,
+ cairo_rectangle_int_t *extents)
+{
+ cairo_status_t status;
+ cairo_bool_t is_empty;
+
+ _cairo_surface_operation_extents (surface, op, source, clip, extents);
+
+ if (_cairo_operator_bounded_by_mask (op)) {
+ cairo_rectangle_int_t glyph_extents;
+
+ status = _cairo_scaled_font_glyph_device_extents (scaled_font,
+ glyphs,
+ num_glyphs,
+ &glyph_extents,
+ NULL);
+ if (unlikely (status))
+ return status;
+
+ is_empty = _cairo_rectangle_intersect (extents, &glyph_extents);
+ }
+
+ return CAIRO_STATUS_SUCCESS;
+}
+
cairo_surface_t *
_cairo_surface_create_in_error (cairo_status_t status)
{
diff --git a/src/cairoint.h b/src/cairoint.h
index d0e34095..f6a45596 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -1950,6 +1950,55 @@ _cairo_surface_show_text_glyphs (cairo_surface_t *surface,
cairo_clip_t *clip);
cairo_private cairo_status_t
+_cairo_surface_paint_extents (cairo_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_clip_t *clip,
+ cairo_rectangle_int_t *extents);
+
+cairo_private cairo_status_t
+_cairo_surface_mask_extents (cairo_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ const cairo_pattern_t *mask,
+ cairo_clip_t *clip,
+ cairo_rectangle_int_t *extents);
+
+cairo_private cairo_status_t
+_cairo_surface_stroke_extents (cairo_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_path_fixed_t *path,
+ cairo_stroke_style_t *style,
+ const cairo_matrix_t *ctm,
+ const cairo_matrix_t *ctm_inverse,
+ double tolerance,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip,
+ cairo_rectangle_int_t *extents);
+
+cairo_private cairo_status_t
+_cairo_surface_fill_extents (cairo_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_path_fixed_t *path,
+ cairo_fill_rule_t fill_rule,
+ double tolerance,
+ cairo_antialias_t antialias,
+ cairo_clip_t *clip,
+ cairo_rectangle_int_t *extents);
+
+cairo_private cairo_status_t
+_cairo_surface_glyphs_extents (cairo_surface_t *surface,
+ cairo_operator_t op,
+ const cairo_pattern_t *source,
+ cairo_glyph_t *glyphs,
+ int num_glyphs,
+ cairo_scaled_font_t *scaled_font,
+ cairo_clip_t *clip,
+ cairo_rectangle_int_t *extents);
+
+cairo_private cairo_status_t
_cairo_surface_composite_trapezoids (cairo_operator_t op,
const cairo_pattern_t *pattern,
cairo_surface_t *dst,