mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2026-02-05 01:50:27 +01:00
Implement path clipping and refactor _cairo_gstate_clip() out in three different functions corresponding to the three different clipping modes.
Add NULL pointers for intersect_clip_path. New test case to exercise PDF clipping code.
This commit is contained in:
parent
663e39a63c
commit
476fe9a66e
15 changed files with 585 additions and 133 deletions
36
ChangeLog
36
ChangeLog
|
|
@ -1,3 +1,39 @@
|
|||
2005-06-14 Kristian Høgsberg <krh@redhat.com>
|
||||
|
||||
* src/cairo-gstate-private.h:
|
||||
* src/cairo-gstate.c: (_cairo_gstate_init),
|
||||
(_cairo_gstate_init_copy), (_cairo_gstate_fini),
|
||||
(_cairo_gstate_set_clip), (_composite_trap_region),
|
||||
(_cairo_gstate_fill), (_cairo_gstate_reset_clip),
|
||||
(_cairo_gstate_intersect_clip_path), (_cairo_clip_path_reference),
|
||||
(_cairo_clip_path_destroy), (_cairo_gstate_intersect_clip_region),
|
||||
(_cairo_gstate_intersect_clip_mask), (_cairo_gstate_clip):
|
||||
* src/cairo-pdf-surface.c:
|
||||
(_cairo_pdf_surface_create_for_document),
|
||||
(_cairo_pdf_path_move_to), (_cairo_pdf_path_line_to),
|
||||
(_cairo_pdf_path_close_path), (_cairo_pdf_surface_fill_path),
|
||||
(_cairo_pdf_surface_intersect_clip_path),
|
||||
(_cairo_pdf_document_add_page):
|
||||
* src/cairo-surface.c: (_cairo_surface_get_clip_mode),
|
||||
(_cairo_surface_fill_path), (_cairo_surface_reset_clip),
|
||||
(_cairo_surface_set_clip_path_recursive),
|
||||
(_cairo_surface_set_clip_path):
|
||||
* src/cairoint.h: Implement path clipping and refactor
|
||||
_cairo_gstate_clip() out in three different functions
|
||||
corresponding to the three different clipping modes.
|
||||
|
||||
* src/cairo-glitz-surface.c:
|
||||
* src/cairo-ps-surface.c:
|
||||
* src/cairo-win32-surface.c:
|
||||
* src/cairo-xcb-surface.c:
|
||||
* src/cairo-xlib-surface.c:
|
||||
* src/cairo-image-surface.c:
|
||||
* src/cairo-quartz-surface.c: Add NULL pointers for
|
||||
intersect_clip_path.
|
||||
|
||||
* test/Makefile.am:
|
||||
* test/pdf-clip.c: New test case to exercise PDF clipping code.
|
||||
|
||||
2005-06-14 Carl Worth <cworth@cworth.org>
|
||||
|
||||
* src/cairo-glitz-surface.c: (_cairo_glitz_surface_create_similar),
|
||||
|
|
|
|||
|
|
@ -2132,6 +2132,7 @@ static const cairo_surface_backend_t cairo_glitz_surface_backend = {
|
|||
NULL, /* copy_page */
|
||||
NULL, /* show_page */
|
||||
_cairo_glitz_surface_set_clip_region,
|
||||
NULL, /* intersect_clip_path */
|
||||
_cairo_glitz_surface_get_extents,
|
||||
_cairo_glitz_surface_show_glyphs
|
||||
};
|
||||
|
|
|
|||
|
|
@ -36,7 +36,19 @@
|
|||
#ifndef CAIRO_GSTATE_PRIVATE_H
|
||||
#define CAIRO_GSTATE_PRIVATE_H
|
||||
|
||||
#include "cairo-path-fixed-private.h"
|
||||
|
||||
struct _cairo_clip_path {
|
||||
unsigned int ref_count;
|
||||
cairo_path_fixed_t path;
|
||||
cairo_fill_rule_t fill_rule;
|
||||
double tolerance;
|
||||
cairo_clip_path_t *prev;
|
||||
};
|
||||
|
||||
typedef struct _cairo_clip {
|
||||
cairo_clip_mode_t mode;
|
||||
|
||||
/*
|
||||
* Mask-based clipping for cases where the backend
|
||||
* clipping isn't sufficiently able.
|
||||
|
|
@ -59,8 +71,10 @@ typedef struct _cairo_clip {
|
|||
*/
|
||||
pixman_region16_t *region;
|
||||
/*
|
||||
* XXX add clip paths here
|
||||
* If the surface supports path clipping, we store the list of
|
||||
* clipping paths that has been set here as a linked list.
|
||||
*/
|
||||
cairo_clip_path_t *path;
|
||||
} cairo_clip_t;
|
||||
|
||||
struct _cairo_gstate {
|
||||
|
|
|
|||
|
|
@ -70,6 +70,12 @@ _cairo_gstate_unset_font (cairo_gstate_t *gstate);
|
|||
static void
|
||||
_cairo_rectangle_intersect (cairo_rectangle_t *dest, cairo_rectangle_t *src);
|
||||
|
||||
static void
|
||||
_cairo_clip_path_reference (cairo_clip_path_t *clip_path);
|
||||
|
||||
static void
|
||||
_cairo_clip_path_destroy (cairo_clip_path_t *clip_path);
|
||||
|
||||
cairo_gstate_t *
|
||||
_cairo_gstate_create (cairo_surface_t *target)
|
||||
{
|
||||
|
|
@ -116,9 +122,11 @@ _cairo_gstate_init (cairo_gstate_t *gstate,
|
|||
CAIRO_GSTATE_DEFAULT_FONT_SIZE,
|
||||
CAIRO_GSTATE_DEFAULT_FONT_SIZE);
|
||||
|
||||
gstate->clip.mode = _cairo_surface_get_clip_mode (target);
|
||||
gstate->clip.region = NULL;
|
||||
gstate->clip.surface = NULL;
|
||||
gstate->clip.serial = 0;
|
||||
gstate->clip.path = NULL;
|
||||
|
||||
_cairo_gstate_identity_matrix (gstate);
|
||||
|
||||
|
|
@ -168,6 +176,7 @@ _cairo_gstate_init_copy (cairo_gstate_t *gstate, cairo_gstate_t *other)
|
|||
|
||||
cairo_surface_reference (gstate->target);
|
||||
cairo_surface_reference (gstate->clip.surface);
|
||||
_cairo_clip_path_reference (gstate->clip.path);
|
||||
|
||||
cairo_pattern_reference (gstate->source);
|
||||
|
||||
|
|
@ -205,6 +214,10 @@ _cairo_gstate_fini (cairo_gstate_t *gstate)
|
|||
cairo_surface_destroy (gstate->clip.surface);
|
||||
gstate->clip.surface = NULL;
|
||||
|
||||
if (gstate->clip.path)
|
||||
_cairo_clip_path_destroy (gstate->clip.path);
|
||||
gstate->clip.path = NULL;
|
||||
|
||||
if (gstate->clip.region)
|
||||
pixman_region_destroy (gstate->clip.region);
|
||||
gstate->clip.region = NULL;
|
||||
|
|
@ -338,7 +351,10 @@ _cairo_gstate_set_clip (cairo_gstate_t *gstate)
|
|||
if (gstate->clip.serial == _cairo_surface_get_current_clip_serial (surface))
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
|
||||
/* check for path clipping here */
|
||||
if (gstate->clip.path)
|
||||
return _cairo_surface_set_clip_path (surface,
|
||||
gstate->clip.path,
|
||||
gstate->clip.serial);
|
||||
|
||||
if (gstate->clip.region)
|
||||
return _cairo_surface_set_clip_region (surface,
|
||||
|
|
@ -1142,9 +1158,8 @@ _composite_trap_region (cairo_gstate_t *gstate,
|
|||
|
||||
if (num_rects > 1) {
|
||||
|
||||
status = _cairo_surface_can_clip_region (gstate->target);
|
||||
if (status)
|
||||
return status;
|
||||
if (gstate->clip.mode != CAIRO_CLIP_MODE_REGION)
|
||||
return CAIRO_INT_STATUS_UNSUPPORTED;
|
||||
|
||||
clip_serial = _cairo_surface_allocate_clip_serial (gstate->target);
|
||||
status = _cairo_surface_set_clip_region (gstate->target,
|
||||
|
|
@ -1438,7 +1453,9 @@ _cairo_gstate_fill (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
|
|||
status = _cairo_surface_fill_path (gstate->operator,
|
||||
gstate->source,
|
||||
gstate->target,
|
||||
path);
|
||||
path,
|
||||
gstate->fill_rule,
|
||||
gstate->tolerance);
|
||||
|
||||
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
|
||||
return status;
|
||||
|
|
@ -1583,83 +1600,124 @@ _cairo_gstate_reset_clip (cairo_gstate_t *gstate)
|
|||
if (gstate->clip.region)
|
||||
pixman_region_destroy (gstate->clip.region);
|
||||
gstate->clip.region = NULL;
|
||||
|
||||
if (gstate->clip.path)
|
||||
_cairo_clip_path_destroy (gstate->clip.path);
|
||||
gstate->clip.path = NULL;
|
||||
|
||||
gstate->clip.serial = 0;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_clip (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
|
||||
static cairo_status_t
|
||||
_cairo_gstate_intersect_clip_path (cairo_gstate_t *gstate,
|
||||
cairo_path_fixed_t *path)
|
||||
{
|
||||
cairo_clip_path_t *clip_path;
|
||||
cairo_status_t status;
|
||||
cairo_pattern_union_t pattern;
|
||||
cairo_traps_t traps;
|
||||
cairo_rectangle_t surface_rect;
|
||||
cairo_box_t extents;
|
||||
cairo_surface_t *surface;
|
||||
pixman_region16_t *region;
|
||||
|
||||
/* Fill the clip region as traps. */
|
||||
if (gstate->clip.mode != CAIRO_CLIP_MODE_PATH)
|
||||
return CAIRO_INT_STATUS_UNSUPPORTED;
|
||||
|
||||
_cairo_traps_init (&traps);
|
||||
status = _cairo_path_fixed_fill_to_traps (path, gstate, &traps);
|
||||
if (status) {
|
||||
_cairo_traps_fini (&traps);
|
||||
clip_path = malloc (sizeof (cairo_clip_path_t));
|
||||
if (clip_path == NULL)
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
|
||||
status = _cairo_path_fixed_init_copy (&clip_path->path, path);
|
||||
if (status)
|
||||
return status;
|
||||
}
|
||||
|
||||
status = _cairo_surface_can_clip_region (gstate->target);
|
||||
clip_path->ref_count = 1;
|
||||
clip_path->fill_rule = gstate->fill_rule;
|
||||
clip_path->tolerance = gstate->tolerance;
|
||||
clip_path->prev = gstate->clip.path;
|
||||
gstate->clip.path = clip_path;
|
||||
gstate->clip.serial = _cairo_surface_allocate_clip_serial (gstate->target);
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static void
|
||||
_cairo_clip_path_reference (cairo_clip_path_t *clip_path)
|
||||
{
|
||||
if (clip_path == NULL)
|
||||
return;
|
||||
|
||||
clip_path->ref_count++;
|
||||
}
|
||||
|
||||
static void
|
||||
_cairo_clip_path_destroy (cairo_clip_path_t *clip_path)
|
||||
{
|
||||
if (clip_path == NULL)
|
||||
return;
|
||||
|
||||
clip_path->ref_count--;
|
||||
if (clip_path->ref_count)
|
||||
return;
|
||||
|
||||
_cairo_path_fixed_fini (&clip_path->path);
|
||||
_cairo_clip_path_destroy (clip_path->prev);
|
||||
free (clip_path);
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_gstate_intersect_clip_region (cairo_gstate_t *gstate,
|
||||
cairo_traps_t *traps)
|
||||
{
|
||||
pixman_region16_t *region;
|
||||
cairo_status_t status;
|
||||
|
||||
if (gstate->clip.mode != CAIRO_CLIP_MODE_REGION)
|
||||
return CAIRO_INT_STATUS_UNSUPPORTED;
|
||||
|
||||
if (status != CAIRO_INT_STATUS_UNSUPPORTED) {
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
/* Check to see if we can represent these traps as a PixRegion. */
|
||||
|
||||
status = _cairo_traps_extract_region (&traps, ®ion);
|
||||
if (status) {
|
||||
_cairo_traps_fini (&traps);
|
||||
return status;
|
||||
}
|
||||
status = _cairo_traps_extract_region (traps, ®ion);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
if (region) {
|
||||
status = CAIRO_STATUS_SUCCESS;
|
||||
|
||||
if (gstate->clip.region == NULL) {
|
||||
gstate->clip.region = region;
|
||||
} else {
|
||||
pixman_region16_t *intersection = pixman_region_create();
|
||||
|
||||
if (pixman_region_intersect (intersection,
|
||||
gstate->clip.region, region)
|
||||
== PIXMAN_REGION_STATUS_SUCCESS) {
|
||||
pixman_region_destroy (gstate->clip.region);
|
||||
gstate->clip.region = intersection;
|
||||
} else {
|
||||
status = CAIRO_STATUS_NO_MEMORY;
|
||||
}
|
||||
pixman_region_destroy (region);
|
||||
}
|
||||
gstate->clip.serial = _cairo_surface_allocate_clip_serial (gstate->target);
|
||||
|
||||
_cairo_traps_fini (&traps);
|
||||
|
||||
return status;
|
||||
}
|
||||
}
|
||||
if (region == NULL)
|
||||
return CAIRO_INT_STATUS_UNSUPPORTED;
|
||||
|
||||
/* Otherwise represent the clip as a mask surface. We create a
|
||||
* new surface the size of the intersection of the old mask
|
||||
* surface and the extents of the new clip path. */
|
||||
|
||||
if (gstate->clip.surface == NULL) {
|
||||
_cairo_traps_extents (&traps, &extents);
|
||||
_cairo_box_round_to_rectangle (&extents, &surface_rect);
|
||||
status = CAIRO_STATUS_SUCCESS;
|
||||
if (gstate->clip.region == NULL) {
|
||||
gstate->clip.region = region;
|
||||
} else {
|
||||
_cairo_traps_extents (&traps, &extents);
|
||||
_cairo_box_round_to_rectangle (&extents, &surface_rect);
|
||||
_cairo_rectangle_intersect (&surface_rect, &gstate->clip.surface_rect);
|
||||
pixman_region16_t *intersection = pixman_region_create();
|
||||
|
||||
if (pixman_region_intersect (intersection,
|
||||
gstate->clip.region, region)
|
||||
== PIXMAN_REGION_STATUS_SUCCESS) {
|
||||
pixman_region_destroy (gstate->clip.region);
|
||||
gstate->clip.region = intersection;
|
||||
} else {
|
||||
status = CAIRO_STATUS_NO_MEMORY;
|
||||
}
|
||||
pixman_region_destroy (region);
|
||||
}
|
||||
gstate->clip.serial = _cairo_surface_allocate_clip_serial (gstate->target);
|
||||
return status;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_gstate_intersect_clip_mask (cairo_gstate_t *gstate,
|
||||
cairo_traps_t *traps)
|
||||
{
|
||||
cairo_pattern_union_t pattern;
|
||||
cairo_box_t extents;
|
||||
cairo_rectangle_t surface_rect;
|
||||
cairo_surface_t *surface;
|
||||
cairo_status_t status;
|
||||
|
||||
/* Represent the clip as a mask surface. We create a new surface
|
||||
* the size of the intersection of the old mask surface and the
|
||||
* extents of the new clip path. */
|
||||
|
||||
_cairo_traps_extents (traps, &extents);
|
||||
_cairo_box_round_to_rectangle (&extents, &surface_rect);
|
||||
|
||||
if (gstate->clip.surface != NULL)
|
||||
_cairo_rectangle_intersect (&surface_rect, &gstate->clip.surface_rect);
|
||||
|
||||
surface = _cairo_surface_create_similar_solid (gstate->target,
|
||||
CAIRO_FORMAT_A8,
|
||||
|
|
@ -1671,7 +1729,7 @@ _cairo_gstate_clip (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
|
|||
|
||||
/* Render the new clipping path into the new mask surface. */
|
||||
|
||||
translate_traps (&traps, -surface_rect.x, -surface_rect.y);
|
||||
translate_traps (traps, -surface_rect.x, -surface_rect.y);
|
||||
_cairo_pattern_init_solid (&pattern.solid, CAIRO_COLOR_WHITE);
|
||||
|
||||
status = _cairo_surface_composite_trapezoids (CAIRO_OPERATOR_IN,
|
||||
|
|
@ -1681,11 +1739,10 @@ _cairo_gstate_clip (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
|
|||
0, 0,
|
||||
surface_rect.width,
|
||||
surface_rect.height,
|
||||
traps.traps,
|
||||
traps.num_traps);
|
||||
traps->traps,
|
||||
traps->num_traps);
|
||||
|
||||
_cairo_pattern_fini (&pattern.base);
|
||||
_cairo_traps_fini (&traps);
|
||||
|
||||
if (status) {
|
||||
cairo_surface_destroy (surface);
|
||||
|
|
@ -1723,7 +1780,34 @@ _cairo_gstate_clip (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
|
|||
gstate->clip.surface = surface;
|
||||
gstate->clip.surface_rect = surface_rect;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
return status;
|
||||
}
|
||||
|
||||
cairo_status_t
|
||||
_cairo_gstate_clip (cairo_gstate_t *gstate, cairo_path_fixed_t *path)
|
||||
{
|
||||
cairo_status_t status;
|
||||
cairo_traps_t traps;
|
||||
|
||||
status = _cairo_gstate_intersect_clip_path (gstate, path);
|
||||
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
|
||||
return status;
|
||||
|
||||
_cairo_traps_init (&traps);
|
||||
status = _cairo_path_fixed_fill_to_traps (path, gstate, &traps);
|
||||
if (status)
|
||||
goto bail;
|
||||
|
||||
status = _cairo_gstate_intersect_clip_region (gstate, &traps);
|
||||
if (status != CAIRO_INT_STATUS_UNSUPPORTED)
|
||||
goto bail;
|
||||
|
||||
status = _cairo_gstate_intersect_clip_mask (gstate, &traps);
|
||||
|
||||
bail:
|
||||
_cairo_traps_fini (&traps);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
|||
|
|
@ -713,6 +713,7 @@ static const cairo_surface_backend_t cairo_image_surface_backend = {
|
|||
NULL, /* copy_page */
|
||||
NULL, /* show_page */
|
||||
_cairo_image_abstract_surface_set_clip_region,
|
||||
NULL, /* intersect_clip_path */
|
||||
_cairo_image_abstract_surface_get_extents,
|
||||
NULL /* show_glyphs */
|
||||
};
|
||||
|
|
|
|||
|
|
@ -188,6 +188,7 @@ struct cairo_pdf_surface {
|
|||
cairo_array_t streams;
|
||||
cairo_array_t alphas;
|
||||
cairo_array_t fonts;
|
||||
cairo_bool_t has_clip;
|
||||
};
|
||||
|
||||
#define DEFAULT_DPI 300
|
||||
|
|
@ -989,6 +990,7 @@ _cairo_pdf_surface_create_for_document (cairo_pdf_document_t *document,
|
|||
_cairo_array_init (&surface->xobjects, sizeof (cairo_pdf_resource_t));
|
||||
_cairo_array_init (&surface->alphas, sizeof (double));
|
||||
_cairo_array_init (&surface->fonts, sizeof (cairo_pdf_resource_t));
|
||||
surface->has_clip = FALSE;
|
||||
|
||||
return &surface->base;
|
||||
}
|
||||
|
|
@ -1638,6 +1640,7 @@ intersect (cairo_line_t *line, cairo_fixed_t y)
|
|||
typedef struct
|
||||
{
|
||||
cairo_output_stream_t *output_stream;
|
||||
cairo_bool_t has_current_point;
|
||||
} pdf_path_info_t;
|
||||
|
||||
static cairo_status_t
|
||||
|
|
@ -1649,6 +1652,7 @@ _cairo_pdf_path_move_to (void *closure, cairo_point_t *point)
|
|||
"%f %f m ",
|
||||
_cairo_fixed_to_double (point->x),
|
||||
_cairo_fixed_to_double (point->y));
|
||||
info->has_current_point = TRUE;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
|
@ -1657,11 +1661,19 @@ static cairo_status_t
|
|||
_cairo_pdf_path_line_to (void *closure, cairo_point_t *point)
|
||||
{
|
||||
pdf_path_info_t *info = closure;
|
||||
const char *pdf_operator;
|
||||
|
||||
if (info->has_current_point)
|
||||
pdf_operator = "l";
|
||||
else
|
||||
pdf_operator = "m";
|
||||
|
||||
_cairo_output_stream_printf (info->output_stream,
|
||||
"%f %f l ",
|
||||
"%f %f %s ",
|
||||
_cairo_fixed_to_double (point->x),
|
||||
_cairo_fixed_to_double (point->y));
|
||||
_cairo_fixed_to_double (point->y),
|
||||
pdf_operator);
|
||||
info->has_current_point = TRUE;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
|
@ -1693,6 +1705,7 @@ _cairo_pdf_path_close_path (void *closure)
|
|||
|
||||
_cairo_output_stream_printf (info->output_stream,
|
||||
"h\r\n");
|
||||
info->has_current_point = FALSE;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
|
@ -1701,15 +1714,16 @@ static cairo_int_status_t
|
|||
_cairo_pdf_surface_fill_path (cairo_operator_t operator,
|
||||
cairo_pattern_t *pattern,
|
||||
void *abstract_dst,
|
||||
cairo_path_fixed_t *path)
|
||||
cairo_path_fixed_t *path,
|
||||
cairo_fill_rule_t fill_rule,
|
||||
double tolerance)
|
||||
{
|
||||
cairo_pdf_surface_t *surface = abstract_dst;
|
||||
cairo_pdf_document_t *document = surface->document;
|
||||
const char *pdf_operator;
|
||||
cairo_status_t status;
|
||||
pdf_path_info_t info;
|
||||
|
||||
return CAIRO_INT_STATUS_UNSUPPORTED;
|
||||
|
||||
emit_pattern (surface, pattern);
|
||||
|
||||
/* After the above switch the current stream should belong to this
|
||||
|
|
@ -1718,6 +1732,7 @@ _cairo_pdf_surface_fill_path (cairo_operator_t operator,
|
|||
document->current_stream == surface->current_stream);
|
||||
|
||||
info.output_stream = document->output_stream;
|
||||
info.has_current_point = FALSE;
|
||||
|
||||
status = _cairo_path_fixed_interpret (path,
|
||||
CAIRO_DIRECTION_FORWARD,
|
||||
|
|
@ -1727,8 +1742,20 @@ _cairo_pdf_surface_fill_path (cairo_operator_t operator,
|
|||
_cairo_pdf_path_close_path,
|
||||
&info);
|
||||
|
||||
switch (fill_rule) {
|
||||
case CAIRO_FILL_RULE_WINDING:
|
||||
pdf_operator = "f";
|
||||
break;
|
||||
case CAIRO_FILL_RULE_EVEN_ODD:
|
||||
pdf_operator = "f*";
|
||||
break;
|
||||
default:
|
||||
ASSERT_NOT_REACHED;
|
||||
}
|
||||
|
||||
_cairo_output_stream_printf (document->output_stream,
|
||||
"f\r\n");
|
||||
"%s\r\n",
|
||||
pdf_operator);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
|
@ -1905,6 +1932,62 @@ _cairo_pdf_surface_show_glyphs (cairo_scaled_font_t *scaled_font,
|
|||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static cairo_int_status_t
|
||||
_cairo_pdf_surface_intersect_clip_path (void *dst,
|
||||
cairo_path_fixed_t *path,
|
||||
cairo_fill_rule_t fill_rule,
|
||||
double tolerance)
|
||||
{
|
||||
cairo_pdf_surface_t *surface = dst;
|
||||
cairo_pdf_document_t *document = surface->document;
|
||||
cairo_output_stream_t *output = document->output_stream;
|
||||
cairo_status_t status;
|
||||
pdf_path_info_t info;
|
||||
const char *pdf_operator;
|
||||
|
||||
_cairo_pdf_surface_ensure_stream (surface);
|
||||
|
||||
if (path == NULL) {
|
||||
if (surface->has_clip)
|
||||
_cairo_output_stream_printf (output, "Q\r\n");
|
||||
surface->has_clip = FALSE;
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (!surface->has_clip) {
|
||||
_cairo_output_stream_printf (output, "q ");
|
||||
surface->has_clip = TRUE;
|
||||
}
|
||||
|
||||
info.output_stream = document->output_stream;
|
||||
info.has_current_point = FALSE;
|
||||
|
||||
status = _cairo_path_fixed_interpret (path,
|
||||
CAIRO_DIRECTION_FORWARD,
|
||||
_cairo_pdf_path_move_to,
|
||||
_cairo_pdf_path_line_to,
|
||||
_cairo_pdf_path_curve_to,
|
||||
_cairo_pdf_path_close_path,
|
||||
&info);
|
||||
|
||||
switch (fill_rule) {
|
||||
case CAIRO_FILL_RULE_WINDING:
|
||||
pdf_operator = "W";
|
||||
break;
|
||||
case CAIRO_FILL_RULE_EVEN_ODD:
|
||||
pdf_operator = "W*";
|
||||
break;
|
||||
default:
|
||||
ASSERT_NOT_REACHED;
|
||||
}
|
||||
|
||||
_cairo_output_stream_printf (document->output_stream,
|
||||
"%s n\r\n",
|
||||
pdf_operator);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
static const cairo_surface_backend_t cairo_pdf_surface_backend = {
|
||||
_cairo_pdf_surface_create_similar,
|
||||
_cairo_pdf_surface_finish,
|
||||
|
|
@ -1919,6 +2002,7 @@ static const cairo_surface_backend_t cairo_pdf_surface_backend = {
|
|||
_cairo_pdf_surface_copy_page,
|
||||
_cairo_pdf_surface_show_page,
|
||||
NULL, /* set_clip_region */
|
||||
_cairo_pdf_surface_intersect_clip_path,
|
||||
_cairo_pdf_surface_get_extents,
|
||||
_cairo_pdf_surface_show_glyphs,
|
||||
_cairo_pdf_surface_fill_path
|
||||
|
|
@ -2237,6 +2321,11 @@ _cairo_pdf_document_add_page (cairo_pdf_document_t *document,
|
|||
|
||||
assert (!document->finished);
|
||||
|
||||
_cairo_pdf_surface_ensure_stream (surface);
|
||||
|
||||
if (surface->has_clip)
|
||||
_cairo_output_stream_printf (output, "Q\r\n");
|
||||
|
||||
_cairo_pdf_document_close_stream (document);
|
||||
|
||||
page_id = _cairo_pdf_document_new_object (document);
|
||||
|
|
|
|||
|
|
@ -372,6 +372,7 @@ static const cairo_surface_backend_t cairo_ps_surface_backend = {
|
|||
_cairo_ps_surface_copy_page,
|
||||
_cairo_ps_surface_show_page,
|
||||
_cairo_ps_surface_set_clip_region,
|
||||
NULL, /* intersect_clip_path */
|
||||
_cairo_ps_surface_get_extents,
|
||||
NULL /* show_glyphs */
|
||||
};
|
||||
|
|
|
|||
|
|
@ -226,6 +226,7 @@ static const struct _cairo_surface_backend cairo_quartz_surface_backend = {
|
|||
NULL, /* copy_page */
|
||||
NULL, /* show_page */
|
||||
_cairo_quartz_surface_set_clip_region,
|
||||
NULL, /* intersect_clip_path */
|
||||
_cairo_quartz_surface_get_extents,
|
||||
NULL /* show_glyphs */
|
||||
};
|
||||
|
|
|
|||
|
|
@ -38,7 +38,7 @@
|
|||
#include <stdlib.h>
|
||||
|
||||
#include "cairoint.h"
|
||||
|
||||
#include "cairo-gstate-private.h"
|
||||
|
||||
void
|
||||
_cairo_surface_init (cairo_surface_t *surface,
|
||||
|
|
@ -115,6 +115,17 @@ _cairo_surface_create_similar_solid (cairo_surface_t *other,
|
|||
return surface;
|
||||
}
|
||||
|
||||
cairo_clip_mode_t
|
||||
_cairo_surface_get_clip_mode (cairo_surface_t *surface)
|
||||
{
|
||||
if (surface->backend->intersect_clip_path != NULL)
|
||||
return CAIRO_CLIP_MODE_PATH;
|
||||
else if (surface->backend->set_clip_region != NULL)
|
||||
return CAIRO_CLIP_MODE_REGION;
|
||||
else
|
||||
return CAIRO_CLIP_MODE_MASK;
|
||||
}
|
||||
|
||||
void
|
||||
cairo_surface_reference (cairo_surface_t *surface)
|
||||
{
|
||||
|
|
@ -644,13 +655,16 @@ _cairo_surface_fill_rectangles (cairo_surface_t *surface,
|
|||
}
|
||||
|
||||
cairo_private cairo_int_status_t
|
||||
_cairo_surface_fill_path (cairo_operator_t operator,
|
||||
cairo_pattern_t *pattern,
|
||||
cairo_surface_t *dst,
|
||||
cairo_path_fixed_t *path)
|
||||
_cairo_surface_fill_path (cairo_operator_t operator,
|
||||
cairo_pattern_t *pattern,
|
||||
cairo_surface_t *dst,
|
||||
cairo_path_fixed_t *path,
|
||||
cairo_fill_rule_t fill_rule,
|
||||
double tolerance)
|
||||
{
|
||||
if (dst->backend->fill_path)
|
||||
return dst->backend->fill_path (operator, pattern, dst, path);
|
||||
return dst->backend->fill_path (operator, pattern, dst, path,
|
||||
fill_rule, tolerance);
|
||||
else
|
||||
return CAIRO_INT_STATUS_UNSUPPORTED;
|
||||
}
|
||||
|
|
@ -837,13 +851,16 @@ _cairo_surface_reset_clip (cairo_surface_t *surface)
|
|||
return CAIRO_STATUS_SURFACE_FINISHED;
|
||||
|
||||
surface->current_clip_serial = 0;
|
||||
#if 0
|
||||
if (surface->backend->clip_path) {
|
||||
status = surface->backend->clip_path (surface, NULL);
|
||||
|
||||
if (surface->backend->intersect_clip_path) {
|
||||
status = surface->backend->intersect_clip_path (surface,
|
||||
NULL,
|
||||
CAIRO_FILL_RULE_WINDING,
|
||||
0);
|
||||
if (status)
|
||||
return status;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (surface->backend->set_clip_region != NULL) {
|
||||
status = surface->backend->set_clip_region (surface, NULL);
|
||||
if (status)
|
||||
|
|
@ -852,23 +869,6 @@ _cairo_surface_reset_clip (cairo_surface_t *surface)
|
|||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* _cairo_surface_can_clip_region:
|
||||
* @surface: the #cairo_surface_t to check for region clipping support
|
||||
*
|
||||
* This function checks whether the specified surface can
|
||||
* support region-based clipping.
|
||||
*/
|
||||
cairo_private cairo_status_t
|
||||
_cairo_surface_can_clip_region (cairo_surface_t *surface)
|
||||
{
|
||||
if (surface->finished)
|
||||
return CAIRO_STATUS_SURFACE_FINISHED;
|
||||
if (surface->backend->set_clip_region == NULL)
|
||||
return CAIRO_INT_STATUS_UNSUPPORTED;
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/**
|
||||
* _cairo_surface_set_clip_region:
|
||||
* @surface: the #cairo_surface_t to reset the clip on
|
||||
|
|
@ -893,22 +893,64 @@ _cairo_surface_set_clip_region (cairo_surface_t *surface,
|
|||
return surface->backend->set_clip_region (surface, region);
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* new interfaces for path-based clipping */
|
||||
cairo_private cairo_status_t
|
||||
_cairo_surface_can_clip_path (cairo_surface_t *surface)
|
||||
static cairo_status_t
|
||||
_cairo_surface_set_clip_path_recursive (cairo_surface_t *surface,
|
||||
cairo_clip_path_t *clip_path)
|
||||
{
|
||||
cairo_status_t status;
|
||||
|
||||
if (clip_path == NULL)
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
|
||||
status = _cairo_surface_set_clip_path_recursive (surface, clip_path->prev);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
return surface->backend->intersect_clip_path (surface,
|
||||
&clip_path->path,
|
||||
clip_path->fill_rule,
|
||||
clip_path->tolerance);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* _cairo_surface_set_clip_path:
|
||||
* @surface: the #cairo_surface_t to reset the clip on
|
||||
* @path: the path to intersect against the current clipping path
|
||||
* @fill_rule: fill rule to use for clipping
|
||||
* @tolerance: tesselation to use for tesselating clipping path
|
||||
* @serial: the clip serial number associated with the region
|
||||
*
|
||||
* Sets the clipping path to be the intersection of the current
|
||||
* clipping path of the surface and the given path.
|
||||
**/
|
||||
cairo_private cairo_status_t
|
||||
_cairo_surface_clip_path (cairo_surface_t *surface,
|
||||
cairo_path_fixed_t *path,
|
||||
unsigned int serial)
|
||||
_cairo_surface_set_clip_path (cairo_surface_t *surface,
|
||||
cairo_clip_path_t *clip_path,
|
||||
unsigned int serial)
|
||||
{
|
||||
surface->current_clip_serial = clip_serial;
|
||||
return surface->backend->clip_path (surface, path);
|
||||
cairo_status_t status;
|
||||
|
||||
if (surface->finished)
|
||||
return CAIRO_STATUS_SURFACE_FINISHED;
|
||||
|
||||
assert (surface->backend->intersect_clip_path != NULL);
|
||||
|
||||
status = surface->backend->intersect_clip_path (surface,
|
||||
NULL,
|
||||
CAIRO_FILL_RULE_WINDING,
|
||||
0);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
status = _cairo_surface_set_clip_path_recursive (surface, clip_path);
|
||||
if (status)
|
||||
return status;
|
||||
|
||||
surface->current_clip_serial = serial;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
#endif
|
||||
|
||||
/**
|
||||
* _cairo_surface_get_extents:
|
||||
|
|
|
|||
|
|
@ -941,6 +941,7 @@ static const cairo_surface_backend_t cairo_win32_surface_backend = {
|
|||
NULL, /* copy_page */
|
||||
NULL, /* show_page */
|
||||
_cairo_win32_surface_set_clip_region,
|
||||
NULL, /* intersect_clip_path */
|
||||
_cairo_win32_surface_get_extents,
|
||||
NULL /* show_glyphs */
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1012,6 +1012,7 @@ static const cairo_surface_backend_t cairo_xcb_surface_backend = {
|
|||
NULL, /* copy_page */
|
||||
NULL, /* show_page */
|
||||
NULL, /* _cairo_xcb_surface_set_clip_region */
|
||||
NULL, /* intersect_clip_path */
|
||||
_cairo_xcb_surface_get_extents,
|
||||
NULL /* show_glyphs */
|
||||
};
|
||||
|
|
|
|||
|
|
@ -1046,6 +1046,7 @@ static const cairo_surface_backend_t cairo_xlib_surface_backend = {
|
|||
NULL, /* copy_page */
|
||||
NULL, /* show_page */
|
||||
_cairo_xlib_surface_set_clip_region,
|
||||
NULL, /* intersect_clip_path */
|
||||
_cairo_xlib_surface_get_extents,
|
||||
_cairo_xlib_surface_show_glyphs
|
||||
};
|
||||
|
|
|
|||
|
|
@ -642,10 +642,43 @@ typedef struct _cairo_surface_backend {
|
|||
cairo_int_status_t
|
||||
(*show_page) (void *surface);
|
||||
|
||||
/* Set given region as the clip region for the surface, replacing
|
||||
* any previously set clip region. Passing in a NULL region will
|
||||
* clear the surface clip region.
|
||||
*
|
||||
* The surface is expected to store the clip region and clip all
|
||||
* following drawing operations against it until the clip region
|
||||
* is cleared of replaced by another clip region.
|
||||
*
|
||||
* Cairo will call this function whenever a clip path can be
|
||||
* represented as a device pixel aligned set of rectangles. When
|
||||
* this is not possible, cairo will use mask surfaces for
|
||||
* clipping.
|
||||
*/
|
||||
cairo_int_status_t
|
||||
(*set_clip_region) (void *surface,
|
||||
pixman_region16_t *region);
|
||||
|
||||
/* Intersect the given path against the clip path currently set in
|
||||
* the surface, using the given fill_rule and tolerance, and set
|
||||
* the result as the new clipping path for the surface. Passing
|
||||
* in a NULL path will clear the surface clipping path.
|
||||
*
|
||||
* The surface is expected to store the resulting clip path and
|
||||
* clip all following drawing operations against it until the clip
|
||||
* path cleared or intersected with a new path.
|
||||
*
|
||||
* If a surface implements this function, set_clip_region() will
|
||||
* never be called and should not be implemented. If this
|
||||
* function is not implemented cairo will use set_clip_region()
|
||||
* (if available) and mask surfaces for clipping.
|
||||
*/
|
||||
cairo_int_status_t
|
||||
(*intersect_clip_path) (void *dst,
|
||||
cairo_path_fixed_t *path,
|
||||
cairo_fill_rule_t fill_rule,
|
||||
double tolerance);
|
||||
|
||||
/* Get the extents of the current surface. For many surface types
|
||||
* this will be as simple as { x=0, y=0, width=surface->width,
|
||||
* height=surface->height}.
|
||||
|
|
@ -683,7 +716,9 @@ typedef struct _cairo_surface_backend {
|
|||
(*fill_path) (cairo_operator_t operator,
|
||||
cairo_pattern_t *pattern,
|
||||
void *dst,
|
||||
cairo_path_fixed_t *path);
|
||||
cairo_path_fixed_t *path,
|
||||
cairo_fill_rule_t fill_rule,
|
||||
double tolerance);
|
||||
|
||||
} cairo_surface_backend_t;
|
||||
|
||||
|
|
@ -695,6 +730,12 @@ typedef struct _cairo_format_masks {
|
|||
unsigned long blue_mask;
|
||||
} cairo_format_masks_t;
|
||||
|
||||
typedef enum _cairo_clip_mode {
|
||||
CAIRO_CLIP_MODE_PATH,
|
||||
CAIRO_CLIP_MODE_REGION,
|
||||
CAIRO_CLIP_MODE_MASK
|
||||
} cairo_clip_mode_t;
|
||||
|
||||
struct _cairo_surface {
|
||||
const cairo_surface_backend_t *backend;
|
||||
|
||||
|
|
@ -1381,6 +1422,9 @@ cairo_private void
|
|||
_cairo_surface_init (cairo_surface_t *surface,
|
||||
const cairo_surface_backend_t *backend);
|
||||
|
||||
cairo_private cairo_clip_mode_t
|
||||
_cairo_surface_get_clip_mode (cairo_surface_t *surface);
|
||||
|
||||
cairo_private cairo_status_t
|
||||
_cairo_surface_fill_rectangle (cairo_surface_t *surface,
|
||||
cairo_operator_t operator,
|
||||
|
|
@ -1412,10 +1456,12 @@ _cairo_surface_fill_rectangles (cairo_surface_t *surface,
|
|||
int num_rects);
|
||||
|
||||
cairo_private cairo_int_status_t
|
||||
_cairo_surface_fill_path (cairo_operator_t operator,
|
||||
cairo_pattern_t *pattern,
|
||||
cairo_surface_t *dst,
|
||||
cairo_path_fixed_t *path);
|
||||
_cairo_surface_fill_path (cairo_operator_t operator,
|
||||
cairo_pattern_t *pattern,
|
||||
cairo_surface_t *dst,
|
||||
cairo_path_fixed_t *path,
|
||||
cairo_fill_rule_t fill_rule,
|
||||
double tolerance);
|
||||
|
||||
cairo_private cairo_status_t
|
||||
_cairo_surface_composite_trapezoids (cairo_operator_t operator,
|
||||
|
|
@ -1474,24 +1520,17 @@ _cairo_surface_allocate_clip_serial (cairo_surface_t *surface);
|
|||
cairo_private cairo_status_t
|
||||
_cairo_surface_reset_clip (cairo_surface_t *surface);
|
||||
|
||||
cairo_private cairo_status_t
|
||||
_cairo_surface_can_clip_region (cairo_surface_t *surface);
|
||||
|
||||
cairo_private cairo_status_t
|
||||
_cairo_surface_set_clip_region (cairo_surface_t *surface,
|
||||
pixman_region16_t *region,
|
||||
unsigned int serial);
|
||||
|
||||
#if 0
|
||||
/* new interfaces for path-based clipping */
|
||||
cairo_private cairo_status_t
|
||||
_cairo_surface_can_clip_path (cairo_surface_t *surface);
|
||||
typedef struct _cairo_clip_path cairo_clip_path_t;
|
||||
|
||||
cairo_private cairo_status_t
|
||||
_cairo_surface_clip_path (cairo_surface_t *surface,
|
||||
cairo_path_fixed_t *path,
|
||||
unsigned int serial);
|
||||
#endif
|
||||
_cairo_surface_set_clip_path (cairo_surface_t *surface,
|
||||
cairo_clip_path_t *clip_path,
|
||||
unsigned int serial);
|
||||
|
||||
cairo_private cairo_status_t
|
||||
_cairo_surface_get_extents (cairo_surface_t *surface,
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ user-data \
|
|||
rel-path
|
||||
|
||||
if CAIRO_HAS_PDF_SURFACE
|
||||
TESTS += pdf-surface
|
||||
TESTS += pdf-surface pdf-clip
|
||||
endif
|
||||
|
||||
if CAIRO_HAS_PS_SURFACE
|
||||
|
|
@ -148,6 +148,7 @@ paint_LDADD = $(LDADDS)
|
|||
paint_with_alpha_LDADD = $(LDADDS)
|
||||
path_data_LDADD = $(LDADDS)
|
||||
pdf_surface_LDADD = $(LDADDS)
|
||||
pdf_clip_LDADD = $(LDADDS)
|
||||
ps_surface_LDADD = $(LDADDS)
|
||||
pixman_rotate_LDADD = $(LDADDS)
|
||||
scale_source_surface_paint_LDADD = $(LDADDS)
|
||||
|
|
@ -171,4 +172,10 @@ xlib_surface_LDADD = $(LDADDS)
|
|||
noinst_PROGRAMS = imagediff
|
||||
imagediff_LDADD = $(LDADDS)
|
||||
|
||||
CLEANFILES = *-out.png *-diff.png *.log ps-surface.ps pdf-surface.pdf
|
||||
CLEANFILES = \
|
||||
*-out.png \
|
||||
*-diff.png \
|
||||
*.log \
|
||||
ps-surface.ps \
|
||||
pdf-surface.pdf \
|
||||
pdf-clip.pdf
|
||||
|
|
|
|||
134
test/pdf-clip.c
Normal file
134
test/pdf-clip.c
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
/*
|
||||
* Copyright © 2005 Red Hat, Inc.
|
||||
*
|
||||
* 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
|
||||
* Red Hat, Inc. not be used in advertising or publicity pertaining to
|
||||
* distribution of the software without specific, written prior
|
||||
* permission. Red Hat, Inc. makes no representations about the
|
||||
* suitability of this software for any purpose. It is provided "as
|
||||
* is" without express or implied warranty.
|
||||
*
|
||||
* RED HAT, INC. DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
|
||||
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
||||
* FITNESS, IN NO EVENT SHALL RED HAT, INC. 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: Kristian Høgsberg <krh@redhat.com>
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include <cairo-pdf.h>
|
||||
#include "cairo-test.h"
|
||||
|
||||
/* Test PDF clipping */
|
||||
|
||||
#define WIDTH_IN_POINTS 600
|
||||
#define HEIGHT_IN_POINTS 600
|
||||
|
||||
static void
|
||||
test_clip (cairo_t *cr, double width, double height)
|
||||
{
|
||||
cairo_t *cr2;
|
||||
|
||||
/* Basic test; set a square clip and draw a circle to be clipped
|
||||
* against it.*/
|
||||
|
||||
cairo_rectangle (cr, 100, 100, 400, 400);
|
||||
cairo_clip (cr);
|
||||
cairo_arc (cr, 300, 300, 210, 0, 2 * M_PI);
|
||||
cairo_set_source_rgb (cr, 1, 0, 0);
|
||||
cairo_fill (cr);
|
||||
|
||||
/* Add a plus shaped clip path to the square clip and draw a big
|
||||
* green square to test the new clip path. */
|
||||
|
||||
cairo_save (cr);
|
||||
|
||||
cairo_rectangle (cr, 250, 100, 100, 400);
|
||||
cairo_rectangle (cr, 100, 250, 400, 100);
|
||||
cairo_clip (cr);
|
||||
|
||||
cairo_rectangle (cr, 0, 0, 600, 600);
|
||||
cairo_set_source_rgb (cr, 0, 1, 0);
|
||||
cairo_fill (cr);
|
||||
|
||||
cairo_restore (cr);
|
||||
|
||||
/* Set a bezier shape in addition to the rectangle clip set before
|
||||
* the cairo_save() to verify that we successfully removed the
|
||||
* plus shaped clip path and can set a new clip.*/
|
||||
|
||||
cairo_move_to (cr, 600, 0);
|
||||
cairo_curve_to (cr, 300, 600, 0, 300, 600, 0);
|
||||
cairo_clip (cr);
|
||||
|
||||
cairo_rectangle (cr, 0, 0, 600, 600);
|
||||
cairo_set_source_rgb (cr, 0, 0, 1);
|
||||
cairo_fill (cr);
|
||||
|
||||
/* Create a new context for this surface to test overlapped
|
||||
* drawing from two contexts */
|
||||
cr2 = cairo_create (cairo_get_target (cr));
|
||||
|
||||
/* Using the new context, draw a black vertical line, which should
|
||||
* appear unclipped on top of everything drawn so far. */
|
||||
cairo_move_to (cr2, 110, 0);
|
||||
cairo_line_to (cr2, 110, 600);
|
||||
cairo_stroke (cr2);
|
||||
|
||||
/* Using the first context, draw another black vertical line.
|
||||
* This line should be clipped agaist the bezier clipping path set
|
||||
* earlier. */
|
||||
cairo_set_source_rgb (cr, 0, 0, 0);
|
||||
cairo_move_to (cr, 400, 0);
|
||||
cairo_line_to (cr, 400, 600);
|
||||
cairo_stroke (cr);
|
||||
|
||||
cairo_destroy (cr2);
|
||||
|
||||
/* Test reset clip. Draw a transparent black circle over
|
||||
* everything. Specifically, make sure the circle extends outside
|
||||
* the square clip set at the top of this function. */
|
||||
cairo_reset_clip (cr);
|
||||
cairo_arc (cr, 300, 300, 220, 0, 2 * M_PI);
|
||||
cairo_set_source_rgba (cr, 0, 0, 0, 0.2);
|
||||
cairo_fill (cr);
|
||||
}
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
cairo_t *cr;
|
||||
const char *filename = "pdf-clip.pdf";
|
||||
cairo_surface_t *surface;
|
||||
|
||||
printf("\n");
|
||||
|
||||
surface = cairo_pdf_surface_create (filename,
|
||||
WIDTH_IN_POINTS, HEIGHT_IN_POINTS);
|
||||
if (surface == NULL) {
|
||||
fprintf (stderr, "Failed to create pdf surface for file %s\n", filename);
|
||||
return CAIRO_TEST_FAILURE;
|
||||
}
|
||||
|
||||
cr = cairo_create (surface);
|
||||
|
||||
test_clip (cr, WIDTH_IN_POINTS, HEIGHT_IN_POINTS);
|
||||
cairo_show_page (cr);
|
||||
|
||||
cairo_destroy (cr);
|
||||
cairo_surface_destroy (surface);
|
||||
|
||||
printf ("pdf-surface: Please check %s to make sure it looks happy.\n",
|
||||
filename);
|
||||
|
||||
return 0;
|
||||
}
|
||||
Loading…
Add table
Reference in a new issue