ps: Enable native encoding of subsurface patterns.

Carefully handle subsurfaces of a recording surface through the analysis
and paginated surfaces so that we can generate a native pattern for the
vector backends, demonstrated by the PostScript backend.

Nothing remarkable, just a lot of bookkeeping to track the wrapped
surface types and to apply the correct offsets when generating the
subsurface pattern.
This commit is contained in:
Chris Wilson 2010-04-28 14:26:21 +01:00
parent 5fc04bba9f
commit 8ded35fd69
21 changed files with 565 additions and 126 deletions

View file

@ -40,6 +40,7 @@
#include "cairo-error-private.h"
#include "cairo-paginated-private.h"
#include "cairo-recording-surface-private.h"
#include "cairo-surface-subsurface-private.h"
#include "cairo-region-private.h"
typedef struct {
@ -100,10 +101,11 @@ _analyze_recording_surface_pattern (cairo_analysis_surface_t *surface,
cairo_bool_t old_has_ctm;
cairo_matrix_t old_ctm, p2d;
cairo_status_t status;
cairo_surface_t *source;
assert (pattern->type == CAIRO_PATTERN_TYPE_SURFACE);
surface_pattern = (const cairo_surface_pattern_t *) pattern;
assert (_cairo_surface_is_recording (surface_pattern->surface));
assert (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING);
old_ctm = surface->ctm;
old_has_ctm = surface->has_ctm;
@ -115,8 +117,13 @@ _analyze_recording_surface_pattern (cairo_analysis_surface_t *surface,
cairo_matrix_multiply (&surface->ctm, &p2d, &surface->ctm);
surface->has_ctm = ! _cairo_matrix_is_identity (&surface->ctm);
status = _cairo_recording_surface_replay_and_create_regions (surface_pattern->surface,
&surface->base);
source = surface_pattern->surface;
if (source->backend->type == CAIRO_INTERNAL_SURFACE_TYPE_SUBSURFACE) {
cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) source;
source = sub->target;
}
status = _cairo_recording_surface_replay_and_create_regions (source, &surface->base);
surface->ctm = old_ctm;
surface->has_ctm = old_has_ctm;

View file

@ -362,6 +362,7 @@ _paint_page (cairo_paginated_surface_t *surface)
CAIRO_PAGINATED_MODE_RENDER);
status = _cairo_recording_surface_replay_region (surface->recording_surface,
NULL,
surface->target,
CAIRO_RECORDING_REGION_NATIVE);
assert (status != CAIRO_INT_STATUS_UNSUPPORTED);

View file

@ -2224,7 +2224,9 @@ _cairo_pdf_surface_emit_recording_surface (cairo_pdf_surface_t *surface,
surface->height);
}
status = _cairo_recording_surface_replay_region (recording_surface, &surface->base,
status = _cairo_recording_surface_replay_region (recording_surface,
NULL,
&surface->base,
CAIRO_RECORDING_REGION_NATIVE);
assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
if (unlikely (status))

View file

@ -64,6 +64,7 @@
#include "cairo-paginated-private.h"
#include "cairo-recording-surface-private.h"
#include "cairo-surface-clipper-private.h"
#include "cairo-surface-subsurface-private.h"
#include "cairo-output-stream-private.h"
#include "cairo-type3-glyph-surface-private.h"
#include "cairo-image-info-private.h"
@ -1642,7 +1643,7 @@ _cairo_ps_surface_analyze_surface_pattern_transparency (cairo_ps_surface_t
static cairo_bool_t
surface_pattern_supported (const cairo_surface_pattern_t *pattern)
{
if (_cairo_surface_is_recording (pattern->surface))
if (pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING)
return TRUE;
if (pattern->surface->backend->acquire_source_image == NULL)
@ -1753,7 +1754,7 @@ _cairo_ps_surface_analyze_operation (cairo_ps_surface_t *surface,
if (pattern->type == CAIRO_PATTERN_TYPE_SURFACE) {
cairo_surface_pattern_t *surface_pattern = (cairo_surface_pattern_t *) pattern;
if ( _cairo_surface_is_recording (surface_pattern->surface)) {
if (surface_pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING) {
if (pattern->extend == CAIRO_EXTEND_PAD)
return CAIRO_INT_STATUS_UNSUPPORTED;
else
@ -2431,7 +2432,81 @@ _cairo_ps_surface_emit_recording_surface (cairo_ps_surface_t *surface,
surface->page_bbox.height);
}
status = _cairo_recording_surface_replay_region (recording_surface, &surface->base,
status = _cairo_recording_surface_replay_region (recording_surface,
NULL,
&surface->base,
CAIRO_RECORDING_REGION_NATIVE);
assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
if (unlikely (status))
return status;
status = _cairo_pdf_operators_flush (&surface->pdf_operators);
if (unlikely (status))
return status;
_cairo_output_stream_printf (surface->stream, " Q\n");
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;
_cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface->pdf_operators,
&surface->cairo_to_ps);
return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t
_cairo_ps_surface_emit_recording_subsurface (cairo_ps_surface_t *surface,
cairo_surface_t *recording_surface,
const cairo_rectangle_int_t *extents)
{
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_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;
#if DEBUG_PS
_cairo_output_stream_printf (surface->stream,
"%% _cairo_ps_surface_emit_recording_subsurface (%d, %d), (%d, %d)\n",
extents->x, extents->y,
extents->width, extents->height);
#endif
surface->page_bbox.x = surface->page_bbox.y = 0;
surface->page_bbox.width = surface->width = extents->width;
surface->page_bbox.height = surface->height = extents->height;
surface->current_pattern_is_solid_color = FALSE;
_cairo_pdf_operators_reset (&surface->pdf_operators);
cairo_matrix_init (&surface->cairo_to_ps, 1, 0, 0, -1, 0, surface->height);
_cairo_pdf_operators_set_cairo_to_pdf_matrix (&surface->pdf_operators,
&surface->cairo_to_ps);
_cairo_output_stream_printf (surface->stream, " q\n");
if (recording_surface->content == CAIRO_CONTENT_COLOR) {
surface->content = CAIRO_CONTENT_COLOR;
_cairo_output_stream_printf (surface->stream,
" 0 g %d %d %d %d rectfill\n",
surface->page_bbox.x,
surface->page_bbox.y,
surface->page_bbox.width,
surface->page_bbox.height);
}
status = _cairo_recording_surface_replay_region (recording_surface,
extents,
&surface->base,
CAIRO_RECORDING_REGION_NATIVE);
assert (status != CAIRO_INT_STATUS_UNSUPPORTED);
if (unlikely (status))
@ -2515,18 +2590,25 @@ _cairo_ps_surface_acquire_surface (cairo_ps_surface_t *surface,
surface->acquired_image = NULL;
surface->image = NULL;
if (_cairo_surface_is_recording (pattern->surface)) {
cairo_recording_surface_t *recording_surface = (cairo_recording_surface_t *) pattern->surface;
cairo_box_t bbox;
cairo_rectangle_int_t extents;
if (pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING) {
if (pattern->surface->backend->type == CAIRO_INTERNAL_SURFACE_TYPE_SUBSURFACE) {
cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) pattern->surface;
status = _cairo_recording_surface_get_bbox (recording_surface, &bbox, NULL);
if (unlikely (status))
return status;
*width = sub->extents.width;
*height = sub->extents.height;
} else {
cairo_recording_surface_t *recording_surface = (cairo_recording_surface_t *) pattern->surface;
cairo_box_t bbox;
cairo_rectangle_int_t extents;
_cairo_box_round_to_rectangle (&bbox, &extents);
*width = extents.width;
*height =extents.height;
status = _cairo_recording_surface_get_bbox (recording_surface, &bbox, NULL);
if (unlikely (status))
return status;
_cairo_box_round_to_rectangle (&bbox, &extents);
*width = extents.width;
*height = extents.height;
}
return CAIRO_STATUS_SUCCESS;
} else {
status = _cairo_surface_acquire_source_image (pattern->surface,
@ -2596,10 +2678,15 @@ _cairo_ps_surface_emit_surface (cairo_ps_surface_t *surface,
{
cairo_status_t status;
if (_cairo_surface_is_recording (pattern->surface)) {
cairo_surface_t *recording_surface = pattern->surface;
if (pattern->surface->type == CAIRO_SURFACE_TYPE_RECORDING) {
cairo_surface_t *source = pattern->surface;
status = _cairo_ps_surface_emit_recording_surface (surface, recording_surface);
if (source->backend->type == CAIRO_INTERNAL_SURFACE_TYPE_SUBSURFACE) {
cairo_surface_subsurface_t *sub = (cairo_surface_subsurface_t *) source;
status = _cairo_ps_surface_emit_recording_subsurface (surface, sub->target, &sub->extents);
} else {
status = _cairo_ps_surface_emit_recording_surface (surface, source);
}
} else {
if (pattern->base.extend != CAIRO_EXTEND_PAD) {
status = _cairo_ps_surface_emit_jpeg_image (surface, pattern->surface,
@ -2622,7 +2709,7 @@ _cairo_ps_surface_release_surface (cairo_ps_surface_t *surface,
if (surface->image != surface->acquired_image)
cairo_surface_destroy (&surface->image->base);
if (! _cairo_surface_is_recording (pattern->surface)) {
if (pattern->surface->type != CAIRO_SURFACE_TYPE_RECORDING) {
_cairo_surface_release_source_image (pattern->surface,
surface->acquired_image,
surface->image_extra);

View file

@ -157,6 +157,7 @@ _cairo_recording_surface_replay_and_create_regions (cairo_surface_t *surface,
cairo_surface_t *target);
cairo_private cairo_status_t
_cairo_recording_surface_replay_region (cairo_surface_t *surface,
const cairo_rectangle_int_t *surface_extents,
cairo_surface_t *target,
cairo_recording_region_type_t region);

View file

@ -786,6 +786,7 @@ _cairo_recording_surface_get_path (cairo_surface_t *surface,
#define _clip(c) ((c)->header.clip.path ? &(c)->header.clip : NULL)
static cairo_status_t
_cairo_recording_surface_replay_internal (cairo_surface_t *surface,
const cairo_rectangle_int_t *surface_extents,
cairo_surface_t *target,
cairo_recording_replay_type_t type,
cairo_recording_region_type_t region)
@ -802,13 +803,17 @@ _cairo_recording_surface_replay_internal (cairo_surface_t *surface,
if (unlikely (target->status))
return _cairo_surface_set_error (surface, target->status);
assert (_cairo_surface_is_recording (surface));
_cairo_surface_wrapper_init (&wrapper, target);
_cairo_surface_wrapper_set_extents (&wrapper, surface_extents);
recording_surface = (cairo_recording_surface_t *) surface;
status = CAIRO_STATUS_SUCCESS;
num_elements = recording_surface->commands.num_elements;
elements = _cairo_array_index (&recording_surface->commands, 0);
for (i = recording_surface->replay_start_idx; i < num_elements; i++) {
cairo_command_t *command = elements[i];
@ -975,7 +980,7 @@ cairo_status_t
_cairo_recording_surface_replay (cairo_surface_t *surface,
cairo_surface_t *target)
{
return _cairo_recording_surface_replay_internal (surface,
return _cairo_recording_surface_replay_internal (surface, NULL,
target,
CAIRO_RECORDING_REPLAY,
CAIRO_RECORDING_REGION_ALL);
@ -991,7 +996,7 @@ cairo_status_t
_cairo_recording_surface_replay_and_create_regions (cairo_surface_t *surface,
cairo_surface_t *target)
{
return _cairo_recording_surface_replay_internal (surface,
return _cairo_recording_surface_replay_internal (surface, NULL,
target,
CAIRO_RECORDING_CREATE_REGIONS,
CAIRO_RECORDING_REGION_ALL);
@ -999,10 +1004,11 @@ _cairo_recording_surface_replay_and_create_regions (cairo_surface_t *surface,
cairo_status_t
_cairo_recording_surface_replay_region (cairo_surface_t *surface,
const cairo_rectangle_int_t *surface_extents,
cairo_surface_t *target,
cairo_recording_region_type_t region)
{
return _cairo_recording_surface_replay_internal (surface,
return _cairo_recording_surface_replay_internal (surface, surface_extents,
target,
CAIRO_RECORDING_REPLAY,
region);

View file

@ -86,8 +86,10 @@ struct _cairo_surface {
/* A "snapshot" surface is immutable. See _cairo_surface_snapshot. */
cairo_surface_t *snapshot_of;
cairo_surface_func_t snapshot_detach;
/* current snapshots of this surface, or place upon snapshot list */
/* current snapshots of this surface*/
cairo_list_t snapshots;
/* place upon snapshot list */
cairo_list_t snapshot;
/*
* Surface font options, falling back to backend's default options,

View file

@ -41,8 +41,10 @@
struct _cairo_surface_subsurface {
cairo_surface_t base;
cairo_surface_t *target;
cairo_rectangle_int_t extents;
cairo_surface_t *target;
cairo_bool_t owns_target;
};
#endif /* CAIRO_SURFACE_SUBSURFACE_PRIVATE_H */

View file

@ -36,17 +36,26 @@
#include "cairoint.h"
#include "cairo-error-private.h"
#include "cairo-recording-surface-private.h"
#include "cairo-surface-offset-private.h"
#include "cairo-surface-subsurface-private.h"
static const cairo_surface_backend_t _cairo_surface_subsurface_backend;
static cairo_status_t
_cairo_surface_subsurface_finish (void *abstract_surface)
{
cairo_surface_subsurface_t *surface = abstract_surface;
cairo_status_t status = CAIRO_STATUS_SUCCESS;
if (surface->owns_target) {
cairo_surface_finish (surface->target);
status = surface->target->status;
}
cairo_surface_destroy (surface->target);
return CAIRO_STATUS_SUCCESS;
return status;
}
static cairo_surface_t *
@ -284,6 +293,46 @@ _cairo_surface_subsurface_acquire_source_image (void *abstrac
struct extra *extra;
uint8_t *data;
if (surface->target->type == CAIRO_SURFACE_TYPE_RECORDING) {
cairo_recording_surface_t *meta = (cairo_recording_surface_t *) surface->target;
cairo_surface_t *snapshot;
snapshot = _cairo_surface_has_snapshot (&surface->base,
&_cairo_image_surface_backend);
if (snapshot != NULL) {
*image_out = (cairo_image_surface_t *) cairo_surface_reference (snapshot);
*extra_out = NULL;
return CAIRO_STATUS_SUCCESS;
}
if (! _cairo_surface_has_snapshot (&meta->base,
&_cairo_image_surface_backend))
{
image = (cairo_image_surface_t *)
_cairo_image_surface_create_with_content (meta->content,
surface->extents.width,
surface->extents.height);
if (unlikely (image->base.status))
return image->base.status;
cairo_surface_set_device_offset (&image->base,
-surface->extents.x,
-surface->extents.y);
status = _cairo_recording_surface_replay (&meta->base, &image->base);
if (unlikely (status)) {
cairo_surface_destroy (&image->base);
return status;
}
_cairo_surface_attach_snapshot (&surface->base, &image->base, NULL);
*image_out = image;
*extra_out = NULL;
return CAIRO_STATUS_SUCCESS;
}
}
extra = malloc (sizeof (struct extra));
if (unlikely (extra == NULL))
return _cairo_error (CAIRO_STATUS_NO_MEMORY);
@ -344,10 +393,13 @@ _cairo_surface_subsurface_release_source_image (void *abstract
void *abstract_extra)
{
cairo_surface_subsurface_t *surface = abstract_surface;
struct extra *extra = abstract_extra;
_cairo_surface_release_source_image (surface->target, extra->image, extra->image_extra);
free (extra);
if (abstract_extra != NULL) {
struct extra *extra = abstract_extra;
_cairo_surface_release_source_image (surface->target, extra->image, extra->image_extra);
free (extra);
}
cairo_surface_destroy (&image->base);
}
@ -356,37 +408,23 @@ static cairo_surface_t *
_cairo_surface_subsurface_snapshot (void *abstract_surface)
{
cairo_surface_subsurface_t *surface = abstract_surface;
cairo_image_surface_t *image, *clone;
void *image_extra;
cairo_status_t status;
cairo_surface_subsurface_t *snapshot;
/* XXX Alternatively we could snapshot the target and return a subsurface
* of that.
*/
snapshot = malloc (sizeof (cairo_surface_subsurface_t));
if (unlikely (snapshot == NULL))
return _cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY));
status = _cairo_surface_acquire_source_image (surface->target, &image, &image_extra);
if (unlikely (status))
return _cairo_surface_create_in_error (status);
_cairo_surface_init (&snapshot->base,
&_cairo_surface_subsurface_backend,
NULL, /* device */
surface->target->content);
snapshot->target = _cairo_surface_snapshot (surface->target);
snapshot->owns_target = TRUE;
clone = (cairo_image_surface_t *)
_cairo_image_surface_create_with_pixman_format (NULL,
image->pixman_format,
surface->extents.width,
surface->extents.height,
0);
if (likely (clone->base.status == CAIRO_STATUS_SUCCESS)) {
pixman_image_composite32 (PIXMAN_OP_SRC,
image->pixman_image, NULL, clone->pixman_image,
surface->extents.x, surface->extents.y,
0, 0,
0, 0,
surface->extents.width, surface->extents.height);
clone->base.is_clear = FALSE;
}
snapshot->base.type = snapshot->target->type;
snapshot->extents = surface->extents;
_cairo_surface_release_source_image (surface->target, image, image_extra);
return &clone->base;
return &snapshot->base;
}
static const cairo_surface_backend_t _cairo_surface_subsurface_backend = {
@ -486,6 +524,7 @@ cairo_surface_create_for_rectangle (cairo_surface_t *target,
}
surface->target = cairo_surface_reference (target);
surface->owns_target = FALSE;
return &surface->base;
}

View file

@ -46,13 +46,18 @@ CAIRO_BEGIN_DECLS
struct _cairo_surface_wrapper {
cairo_surface_t *target;
/* any other information? */
cairo_bool_t has_extents;
cairo_rectangle_int_t extents;
};
cairo_private void
_cairo_surface_wrapper_init (cairo_surface_wrapper_t *wrapper,
cairo_surface_t *target);
cairo_private void
_cairo_surface_wrapper_set_extents (cairo_surface_wrapper_t *wrapper,
const cairo_rectangle_int_t *extents);
cairo_private void
_cairo_surface_wrapper_fini (cairo_surface_wrapper_t *wrapper);

View file

@ -71,6 +71,12 @@ _cairo_surface_wrapper_needs_device_transform (cairo_surface_wrapper_t *wrapper)
return ! _cairo_matrix_is_identity (&wrapper->target->device_transform);
}
static cairo_bool_t
_cairo_surface_wrapper_needs_extents_transform (cairo_surface_wrapper_t *wrapper)
{
return wrapper->has_extents && (wrapper->extents.x | wrapper->extents.y);
}
cairo_status_t
_cairo_surface_wrapper_acquire_source_image (cairo_surface_wrapper_t *wrapper,
cairo_image_surface_t **image_out,
@ -100,30 +106,58 @@ _cairo_surface_wrapper_paint (cairo_surface_wrapper_t *wrapper,
cairo_status_t status;
cairo_clip_t clip_copy, *dev_clip = clip;
cairo_pattern_union_t source_copy;
cairo_clip_t target_clip;
if (unlikely (wrapper->target->status))
return wrapper->target->status;
if (clip && clip->all_clipped)
return CAIRO_STATUS_SUCCESS;
if (wrapper->has_extents) {
_cairo_clip_init_copy (&target_clip, clip);
status = _cairo_clip_rectangle (&target_clip, &wrapper->extents);
if (unlikely (status))
goto FINISH;
dev_clip = clip = &target_clip;
}
if (clip && clip->all_clipped) {
status = CAIRO_STATUS_SUCCESS;
goto FINISH;
}
if (_cairo_surface_wrapper_needs_device_transform (wrapper) ||
_cairo_surface_wrapper_needs_extents_transform (wrapper))
{
cairo_matrix_t m;
cairo_matrix_init_identity (&m);
if (_cairo_surface_wrapper_needs_extents_transform (wrapper))
cairo_matrix_translate (&m, -wrapper->extents.x, -wrapper->extents.y);
if (_cairo_surface_wrapper_needs_device_transform (wrapper))
cairo_matrix_multiply (&m, &wrapper->target->device_transform, &m);
if (_cairo_surface_wrapper_needs_device_transform (wrapper)) {
if (clip != NULL) {
status = _cairo_clip_init_copy_transformed (&clip_copy, clip,
&wrapper->target->device_transform);
status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m);
if (unlikely (status))
goto FINISH;
dev_clip = &clip_copy;
}
_copy_transformed_pattern (&source_copy.base, source, &wrapper->target->device_transform_inverse);
status = cairo_matrix_invert (&m);
assert (status == CAIRO_STATUS_SUCCESS);
_copy_transformed_pattern (&source_copy.base, source, &m);
source = &source_copy.base;
}
status = _cairo_surface_paint (wrapper->target, op, source, dev_clip);
FINISH:
if (wrapper->has_extents)
_cairo_clip_reset (&target_clip);
if (dev_clip != clip)
_cairo_clip_reset (dev_clip);
return status;
@ -140,33 +174,61 @@ _cairo_surface_wrapper_mask (cairo_surface_wrapper_t *wrapper,
cairo_clip_t clip_copy, *dev_clip = clip;
cairo_pattern_union_t source_copy;
cairo_pattern_union_t mask_copy;
cairo_clip_t target_clip;
if (unlikely (wrapper->target->status))
return wrapper->target->status;
if (clip && clip->all_clipped)
return CAIRO_STATUS_SUCCESS;
if (wrapper->has_extents) {
_cairo_clip_init_copy (&target_clip, clip);
status = _cairo_clip_rectangle (&target_clip, &wrapper->extents);
if (unlikely (status))
goto FINISH;
dev_clip = clip = &target_clip;
}
if (clip && clip->all_clipped) {
status = CAIRO_STATUS_SUCCESS;
goto FINISH;
}
if (_cairo_surface_wrapper_needs_device_transform (wrapper) ||
_cairo_surface_wrapper_needs_extents_transform (wrapper))
{
cairo_matrix_t m;
cairo_matrix_init_identity (&m);
if (_cairo_surface_wrapper_needs_extents_transform (wrapper))
cairo_matrix_translate (&m, -wrapper->extents.x, -wrapper->extents.y);
if (_cairo_surface_wrapper_needs_device_transform (wrapper))
cairo_matrix_multiply (&m, &wrapper->target->device_transform, &m);
if (_cairo_surface_wrapper_needs_device_transform (wrapper)) {
if (clip != NULL) {
status = _cairo_clip_init_copy_transformed (&clip_copy, clip,
&wrapper->target->device_transform);
status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m);
if (unlikely (status))
goto FINISH;
dev_clip = &clip_copy;
}
_copy_transformed_pattern (&source_copy.base, source, &wrapper->target->device_transform_inverse);
status = cairo_matrix_invert (&m);
assert (status == CAIRO_STATUS_SUCCESS);
_copy_transformed_pattern (&source_copy.base, source, &m);
source = &source_copy.base;
_copy_transformed_pattern (&mask_copy.base, mask, &wrapper->target->device_transform_inverse);
_copy_transformed_pattern (&mask_copy.base, mask, &m);
mask = &mask_copy.base;
}
status = _cairo_surface_mask (wrapper->target, op, source, mask, dev_clip);
FINISH:
if (wrapper->has_extents)
_cairo_clip_reset (&target_clip);
if (dev_clip != clip)
_cairo_clip_reset (dev_clip);
return status;
@ -190,38 +252,65 @@ _cairo_surface_wrapper_stroke (cairo_surface_wrapper_t *wrapper,
cairo_matrix_t dev_ctm = *ctm;
cairo_matrix_t dev_ctm_inverse = *ctm_inverse;
cairo_pattern_union_t source_copy;
cairo_clip_t target_clip;
if (unlikely (wrapper->target->status))
return wrapper->target->status;
if (clip && clip->all_clipped)
return CAIRO_STATUS_SUCCESS;
if (wrapper->has_extents) {
_cairo_clip_init_copy (&target_clip, clip);
status = _cairo_clip_rectangle (&target_clip, &wrapper->extents);
if (unlikely (status))
goto FINISH;
dev_clip = clip = &target_clip;
}
if (clip && clip->all_clipped) {
status = CAIRO_STATUS_SUCCESS;
goto FINISH;
}
if (_cairo_surface_wrapper_needs_device_transform (wrapper) ||
_cairo_surface_wrapper_needs_extents_transform (wrapper))
{
cairo_matrix_t m;
cairo_matrix_init_identity (&m);
if (_cairo_surface_wrapper_needs_extents_transform (wrapper))
cairo_matrix_translate (&m, -wrapper->extents.x, -wrapper->extents.y);
if (_cairo_surface_wrapper_needs_device_transform (wrapper))
cairo_matrix_multiply (&m, &wrapper->target->device_transform, &m);
if (_cairo_surface_wrapper_needs_device_transform (wrapper)) {
status = _cairo_path_fixed_init_copy (&path_copy, dev_path);
if (unlikely (status))
goto FINISH;
_cairo_path_fixed_transform (&path_copy, &wrapper->target->device_transform);
_cairo_path_fixed_transform (&path_copy, &m);
dev_path = &path_copy;
if (clip != NULL) {
status = _cairo_clip_init_copy_transformed (&clip_copy, clip,
&wrapper->target->device_transform);
status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m);
if (unlikely (status))
goto FINISH;
dev_clip = &clip_copy;
}
cairo_matrix_multiply (&dev_ctm, &dev_ctm, &wrapper->target->device_transform);
cairo_matrix_multiply (&dev_ctm_inverse,
&wrapper->target->device_transform_inverse,
&dev_ctm_inverse);
cairo_matrix_multiply (&dev_ctm, &dev_ctm, &m);
_copy_transformed_pattern (&source_copy.base, source, &wrapper->target->device_transform_inverse);
status = cairo_matrix_invert (&m);
assert (status == CAIRO_STATUS_SUCCESS);
cairo_matrix_multiply (&dev_ctm_inverse, &m, &dev_ctm_inverse);
_copy_transformed_pattern (&source_copy.base, source, &m);
source = &source_copy.base;
} else {
}
else
{
if (clip != NULL) {
dev_clip = &clip_copy;
_cairo_clip_init_copy (&clip_copy, clip);
@ -237,6 +326,8 @@ _cairo_surface_wrapper_stroke (cairo_surface_wrapper_t *wrapper,
FINISH:
if (dev_path != path)
_cairo_path_fixed_fini (dev_path);
if (wrapper->has_extents)
_cairo_clip_reset (&target_clip);
if (dev_clip != clip)
_cairo_clip_reset (dev_clip);
return status;
@ -266,41 +357,68 @@ _cairo_surface_wrapper_fill_stroke (cairo_surface_wrapper_t *wrapper,
cairo_matrix_t dev_ctm_inverse = *stroke_ctm_inverse;
cairo_pattern_union_t stroke_source_copy;
cairo_pattern_union_t fill_source_copy;
cairo_clip_t target_clip;
if (unlikely (wrapper->target->status))
return wrapper->target->status;
if (clip && clip->all_clipped)
return CAIRO_STATUS_SUCCESS;
if (wrapper->has_extents) {
_cairo_clip_init_copy (&target_clip, clip);
status = _cairo_clip_rectangle (&target_clip, &wrapper->extents);
if (unlikely (status))
goto FINISH;
dev_clip = clip = &target_clip;
}
if (clip && clip->all_clipped) {
status = CAIRO_STATUS_SUCCESS;
goto FINISH;
}
if (_cairo_surface_wrapper_needs_device_transform (wrapper) ||
_cairo_surface_wrapper_needs_extents_transform (wrapper))
{
cairo_matrix_t m;
cairo_matrix_init_identity (&m);
if (_cairo_surface_wrapper_needs_extents_transform (wrapper))
cairo_matrix_translate (&m, -wrapper->extents.x, -wrapper->extents.y);
if (_cairo_surface_wrapper_needs_device_transform (wrapper))
cairo_matrix_multiply (&m, &wrapper->target->device_transform, &m);
if (_cairo_surface_wrapper_needs_device_transform (wrapper)) {
status = _cairo_path_fixed_init_copy (&path_copy, dev_path);
if (unlikely (status))
goto FINISH;
_cairo_path_fixed_transform (&path_copy, &wrapper->target->device_transform);
_cairo_path_fixed_transform (&path_copy, &m);
dev_path = &path_copy;
if (clip != NULL) {
status = _cairo_clip_init_copy_transformed (&clip_copy, clip,
&wrapper->target->device_transform);
status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m);
if (unlikely (status))
goto FINISH;
dev_clip = &clip_copy;
}
cairo_matrix_multiply (&dev_ctm, &dev_ctm, &wrapper->target->device_transform);
cairo_matrix_multiply (&dev_ctm_inverse,
&wrapper->target->device_transform_inverse,
&dev_ctm_inverse);
cairo_matrix_multiply (&dev_ctm, &dev_ctm, &m);
_copy_transformed_pattern (&stroke_source_copy.base, stroke_source, &wrapper->target->device_transform_inverse);
status = cairo_matrix_invert (&m);
assert (status == CAIRO_STATUS_SUCCESS);
cairo_matrix_multiply (&dev_ctm_inverse, &m, &dev_ctm_inverse);
_copy_transformed_pattern (&stroke_source_copy.base, stroke_source, &m);
stroke_source = &stroke_source_copy.base;
_copy_transformed_pattern (&fill_source_copy.base, fill_source, &wrapper->target->device_transform_inverse);
_copy_transformed_pattern (&fill_source_copy.base, fill_source, &m);
fill_source = &fill_source_copy.base;
} else {
}
else
{
if (clip != NULL) {
dev_clip = &clip_copy;
_cairo_clip_init_copy (&clip_copy, clip);
@ -320,6 +438,8 @@ _cairo_surface_wrapper_fill_stroke (cairo_surface_wrapper_t *wrapper,
FINISH:
if (dev_path != path)
_cairo_path_fixed_fini (dev_path);
if (wrapper->has_extents)
_cairo_clip_reset (&target_clip);
if (dev_clip != clip)
_cairo_clip_reset (dev_clip);
return status;
@ -339,33 +459,61 @@ _cairo_surface_wrapper_fill (cairo_surface_wrapper_t *wrapper,
cairo_path_fixed_t path_copy, *dev_path = path;
cairo_clip_t clip_copy, *dev_clip = clip;
cairo_pattern_union_t source_copy;
cairo_clip_t target_clip;
if (unlikely (wrapper->target->status))
return wrapper->target->status;
if (clip && clip->all_clipped)
return CAIRO_STATUS_SUCCESS;
if (wrapper->has_extents) {
_cairo_clip_init_copy (&target_clip, clip);
status = _cairo_clip_rectangle (&target_clip, &wrapper->extents);
if (unlikely (status))
goto FINISH;
dev_clip = clip = &target_clip;
}
if (clip && clip->all_clipped) {
status = CAIRO_STATUS_SUCCESS;
goto FINISH;
}
if (_cairo_surface_wrapper_needs_device_transform (wrapper) ||
_cairo_surface_wrapper_needs_extents_transform (wrapper))
{
cairo_matrix_t m;
cairo_matrix_init_identity (&m);
if (_cairo_surface_wrapper_needs_extents_transform (wrapper))
cairo_matrix_translate (&m, -wrapper->extents.x, -wrapper->extents.y);
if (_cairo_surface_wrapper_needs_device_transform (wrapper))
cairo_matrix_multiply (&m, &wrapper->target->device_transform, &m);
if (_cairo_surface_wrapper_needs_device_transform (wrapper)) {
status = _cairo_path_fixed_init_copy (&path_copy, dev_path);
if (unlikely (status))
goto FINISH;
_cairo_path_fixed_transform (&path_copy, &wrapper->target->device_transform);
_cairo_path_fixed_transform (&path_copy, &m);
dev_path = &path_copy;
if (clip != NULL) {
status = _cairo_clip_init_copy_transformed (&clip_copy, clip,
&wrapper->target->device_transform);
status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m);
if (unlikely (status))
goto FINISH;
dev_clip = &clip_copy;
}
_copy_transformed_pattern (&source_copy.base, source, &wrapper->target->device_transform_inverse);
status = cairo_matrix_invert (&m);
assert (status == CAIRO_STATUS_SUCCESS);
_copy_transformed_pattern (&source_copy.base, source, &m);
source = &source_copy.base;
} else {
}
else
{
if (clip != NULL) {
dev_clip = &clip_copy;
_cairo_clip_init_copy (&clip_copy, clip);
@ -380,6 +528,8 @@ _cairo_surface_wrapper_fill (cairo_surface_wrapper_t *wrapper,
FINISH:
if (dev_path != path)
_cairo_path_fixed_fini (dev_path);
if (wrapper->has_extents)
_cairo_clip_reset (&target_clip);
if (dev_clip != clip)
_cairo_clip_reset (dev_clip);
return status;
@ -403,6 +553,7 @@ _cairo_surface_wrapper_show_text_glyphs (cairo_surface_wrapper_t *wrapper,
cairo_clip_t clip_copy, *dev_clip = clip;
cairo_glyph_t *dev_glyphs = glyphs;
cairo_pattern_union_t source_copy;
cairo_clip_t target_clip;
if (unlikely (wrapper->target->status))
return wrapper->target->status;
@ -410,15 +561,36 @@ _cairo_surface_wrapper_show_text_glyphs (cairo_surface_wrapper_t *wrapper,
if (glyphs == NULL || num_glyphs == 0)
return CAIRO_STATUS_SUCCESS;
if (clip && clip->all_clipped)
return CAIRO_STATUS_SUCCESS;
if (wrapper->has_extents) {
_cairo_clip_init_copy (&target_clip, clip);
status = _cairo_clip_rectangle (&target_clip, &wrapper->extents);
if (unlikely (status))
goto FINISH;
if (_cairo_surface_wrapper_needs_device_transform (wrapper)) {
dev_clip = clip = &target_clip;
}
if (clip && clip->all_clipped) {
status = CAIRO_STATUS_SUCCESS;
goto FINISH;
}
if (_cairo_surface_wrapper_needs_device_transform (wrapper) ||
_cairo_surface_wrapper_needs_extents_transform (wrapper))
{
cairo_matrix_t m;
int i;
cairo_matrix_init_identity (&m);
if (_cairo_surface_wrapper_needs_extents_transform (wrapper))
cairo_matrix_translate (&m, -wrapper->extents.x, -wrapper->extents.y);
if (_cairo_surface_wrapper_needs_device_transform (wrapper))
cairo_matrix_multiply (&m, &wrapper->target->device_transform, &m);
if (clip != NULL) {
status = _cairo_clip_init_copy_transformed (&clip_copy, clip,
&wrapper->target->device_transform);
status = _cairo_clip_init_copy_transformed (&clip_copy, clip, &m);
if (unlikely (status))
goto FINISH;
@ -433,14 +605,17 @@ _cairo_surface_wrapper_show_text_glyphs (cairo_surface_wrapper_t *wrapper,
for (i = 0; i < num_glyphs; i++) {
dev_glyphs[i] = glyphs[i];
cairo_matrix_transform_point (&wrapper->target->device_transform,
&dev_glyphs[i].x,
&dev_glyphs[i].y);
cairo_matrix_transform_point (&m, &dev_glyphs[i].x, &dev_glyphs[i].y);
}
_copy_transformed_pattern (&source_copy.base, source, &wrapper->target->device_transform_inverse);
status = cairo_matrix_invert (&m);
assert (status == CAIRO_STATUS_SUCCESS);
_copy_transformed_pattern (&source_copy.base, source, &m);
source = &source_copy.base;
} else {
}
else
{
if (clip != NULL) {
dev_clip = &clip_copy;
_cairo_clip_init_copy (&clip_copy, clip);
@ -454,9 +629,12 @@ _cairo_surface_wrapper_show_text_glyphs (cairo_surface_wrapper_t *wrapper,
cluster_flags,
scaled_font,
dev_clip);
FINISH:
if (dev_clip != clip)
_cairo_clip_reset (dev_clip);
if (wrapper->has_extents)
_cairo_clip_reset (&target_clip);
if (dev_glyphs != glyphs)
free (dev_glyphs);
return status;
@ -476,7 +654,28 @@ cairo_bool_t
_cairo_surface_wrapper_get_extents (cairo_surface_wrapper_t *wrapper,
cairo_rectangle_int_t *extents)
{
return _cairo_surface_get_extents (wrapper->target, extents);
if (wrapper->has_extents) {
if (_cairo_surface_get_extents (wrapper->target, extents))
_cairo_rectangle_intersect (extents, &wrapper->extents);
else
*extents = wrapper->extents;
return TRUE;
} else {
return _cairo_surface_get_extents (wrapper->target, extents);
}
}
void
_cairo_surface_wrapper_set_extents (cairo_surface_wrapper_t *wrapper,
const cairo_rectangle_int_t *extents)
{
if (extents != NULL) {
wrapper->extents = *extents;
wrapper->has_extents = TRUE;
} else {
wrapper->has_extents = FALSE;
}
}
void
@ -503,6 +702,7 @@ _cairo_surface_wrapper_init (cairo_surface_wrapper_t *wrapper,
cairo_surface_t *target)
{
wrapper->target = cairo_surface_reference (target);
wrapper->has_extents = FALSE;
}
void

View file

@ -69,6 +69,7 @@ const cairo_surface_t name = { \
NULL, /* snapshot_of */ \
NULL, /* snapshot_detach */ \
{ NULL, NULL }, /* snapshots */ \
{ NULL, NULL }, /* snapshot */ \
{ CAIRO_ANTIALIAS_DEFAULT, /* antialias */ \
CAIRO_SUBPIXEL_ORDER_DEFAULT, /* subpixel_order */ \
CAIRO_HINT_STYLE_DEFAULT, /* hint_style */ \
@ -258,13 +259,10 @@ _cairo_surface_detach_mime_data (cairo_surface_t *surface)
static void
_cairo_surface_detach_snapshots (cairo_surface_t *surface)
{
if (surface->snapshot_of != NULL)
return;
while (_cairo_surface_has_snapshots (surface)) {
_cairo_surface_detach_snapshot (cairo_list_first_entry (&surface->snapshots,
cairo_surface_t,
snapshots));
snapshot));
}
}
@ -274,7 +272,7 @@ _cairo_surface_detach_snapshot (cairo_surface_t *snapshot)
assert (snapshot->snapshot_of != NULL);
snapshot->snapshot_of = NULL;
cairo_list_del (&snapshot->snapshots);
cairo_list_del (&snapshot->snapshot);
if (snapshot->snapshot_detach != NULL)
snapshot->snapshot_detach (snapshot);
@ -288,7 +286,6 @@ _cairo_surface_attach_snapshot (cairo_surface_t *surface,
cairo_surface_func_t detach_func)
{
assert (surface != snapshot);
assert (surface->snapshot_of == NULL);
assert (snapshot->snapshot_of != surface);
cairo_surface_reference (snapshot);
@ -299,7 +296,7 @@ _cairo_surface_attach_snapshot (cairo_surface_t *surface,
snapshot->snapshot_of = surface;
snapshot->snapshot_detach = detach_func;
cairo_list_add (&snapshot->snapshots, &surface->snapshots);
cairo_list_add (&snapshot->snapshot, &surface->snapshots);
assert (_cairo_surface_has_snapshot (surface, snapshot->backend) == snapshot);
}
@ -311,7 +308,7 @@ _cairo_surface_has_snapshot (cairo_surface_t *surface,
cairo_surface_t *snapshot;
cairo_list_foreach_entry (snapshot, cairo_surface_t,
&surface->snapshots, snapshots)
&surface->snapshots, snapshot)
{
/* XXX is_similar? */
if (snapshot->backend == backend)

View file

@ -1070,6 +1070,7 @@ REFERENCE_IMAGES = \
stroke-image.xlib.ref.png \
subsurface.ref.png \
subsurface.image16.ref.png \
subsurface-reflect.ref.png \
subsurface-repeat.ref.png \
subsurface-similar-repeat.ref.png \
surface-pattern-big-scale-down.ref.png \

View file

@ -227,6 +227,7 @@ test_sources = \
spline-decomposition.c \
subsurface.c \
subsurface-repeat.c \
subsurface-reflect.c \
subsurface-similar-repeat.c \
surface-finish-twice.c \
surface-pattern.c \

76
test/subsurface-reflect.c Normal file
View file

@ -0,0 +1,76 @@
/*
* Copyright 2009 Intel Corporation
*
* Permission to use, copy, modify, distribute, and sell this software
* and its documentation for any purpose is hereby granted without
* fee, provided that the above copyright notice appear in all copies
* and that both that copyright notice and this permission notice
* appear in supporting documentation, and that the name of
* Intel not be used in advertising or publicity pertaining to
* distribution of the software without specific, written prior
* permission. Intel makes no representations about the
* suitability of this software for any purpose. It is provided "as
* is" without express or implied warranty.
*
* INTEL CORPORATION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS, IN NO EVENT SHALL INTEL CORPORATION BE LIABLE FOR ANY SPECIAL,
* INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER
* RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR
* IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*
* Author: Chris Wilson <chris@chris-wilson.co.uk>
*/
#include "cairo-test.h"
static cairo_test_status_t
draw (cairo_t *cr, int width, int height)
{
cairo_surface_t *region;
cairo_t *cr_region;
cairo_set_source_rgb (cr, .5, .5, .5);
cairo_paint (cr);
/* fill the centre */
region = cairo_surface_create_for_rectangle (cairo_get_target (cr),
20, 20, 20, 20);
cr_region = cairo_create (region);
cairo_surface_destroy (region);
cairo_set_source_rgb (cr_region, 1, 1, 1);
cairo_rectangle (cr_region, 0, 0, 10, 10);
cairo_fill (cr_region);
cairo_set_source_rgb (cr_region, 1, 0, 0);
cairo_rectangle (cr_region, 10, 0, 10, 10);
cairo_fill (cr_region);
cairo_set_source_rgb (cr_region, 0, 1, 0);
cairo_rectangle (cr_region, 0, 10, 10, 10);
cairo_fill (cr_region);
cairo_set_source_rgb (cr_region, 0, 0, 1);
cairo_rectangle (cr_region, 10, 10, 10, 10);
cairo_fill (cr_region);
cairo_set_source_surface (cr, cairo_get_target (cr_region), 20, 20);
cairo_destroy (cr_region);
/* reflect the pattern around the outside, but do not overwrite...*/
cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_REFLECT);
cairo_rectangle (cr, 0, 0, width, height);
cairo_rectangle (cr, 20, 40, 20, -20);
cairo_fill (cr);
return CAIRO_TEST_SUCCESS;
}
CAIRO_TEST (subsurface_reflect,
"Tests source clipping with reflect",
"subsurface, reflect", /* keywords */
NULL, /* requirements */
60, 60,
NULL, draw)

Binary file not shown.

After

Width:  |  Height:  |  Size: 210 B

View file

@ -36,7 +36,7 @@ draw (cairo_t *cr, int width, int height)
/* fill the centre */
region = cairo_surface_create_for_rectangle (cairo_get_target (cr),
0, 0, 20, 20);
20, 20, 20, 20);
cr_region = cairo_create (region);
cairo_surface_destroy (region);
@ -58,8 +58,12 @@ draw (cairo_t *cr, int width, int height)
cairo_set_source_surface (cr, cairo_get_target (cr_region), 20, 20);
cairo_destroy (cr_region);
/* repeat the pattern around the outside, but do not overwrite...*/
cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_REPEAT);
cairo_paint (cr);
cairo_rectangle (cr, 0, 0, width, height);
cairo_rectangle (cr, 20, 40, 20, -20);
cairo_fill (cr);
return CAIRO_TEST_SUCCESS;
}

View file

@ -40,6 +40,7 @@ draw (cairo_t *cr, int width, int height)
60, 60);
cr_region = cairo_create (similar);
cairo_surface_destroy (similar);
cairo_set_source_rgb (cr_region, .5, .5, .0);
cairo_paint (cr_region);
similar = cairo_surface_reference (cairo_get_target (cr_region));
@ -48,6 +49,7 @@ draw (cairo_t *cr, int width, int height)
/* fill the centre */
region = cairo_surface_create_for_rectangle (similar, 20, 20, 20, 20);
cairo_surface_destroy (similar);
cr_region = cairo_create (region);
cairo_surface_destroy (region);
@ -69,6 +71,7 @@ draw (cairo_t *cr, int width, int height)
cairo_set_source_surface (cr, cairo_get_target (cr_region), 20, 20);
cairo_destroy (cr_region);
cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_REPEAT);
cairo_paint (cr);

View file

@ -63,6 +63,11 @@ draw (cairo_t *cr, int width, int height)
for (i = 0; i < 5; i++) {
cairo_set_source_surface (cr, region[5-i-1], 20 * i, 20);
cairo_paint (cr);
}
for (i = 0; i < 5; i++) {
cairo_set_source_surface (cr, region[5-i-1], 20 * i, 40);
cairo_paint_with_alpha (cr, .5);
}
@ -76,5 +81,5 @@ CAIRO_TEST (subsurface,
"Tests clipping of both source and destination using subsurfaces",
"subsurface", /* keywords */
NULL, /* requirements */
100, 40,
100, 60,
NULL, draw)

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB