summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGraydon Hoare <graydon@redhat.com>2004-05-20 16:42:56 +0000
committerGraydon Hoare <graydon@redhat.com>2004-05-20 16:42:56 +0000
commit23026d5ab65201793ac19b459e3e7e05a090e435 (patch)
tree4e3b57692a89e26b22a29507ad68c2496ea922b9
parentaab2fe8c059cc41451ddf5e0719f18d77ef354f4 (diff)
Add sanity checking feature configury.
Add sanity checking feature. Add sanity checking. Add prototypes. New functions. New function. Use fixed functions. (_cairo_gstate_clip): Arithmetic fixes. (_cairo_gstate_clip_and_composite_trapezoids): (_cairo_gstate_show_surface): (_cairo_gstate_show_text): (_cairo_gstate_show_glyphs): Corrections to clipping. Add XCopyArea fast path. (_cairo_xlib_surface_set_clip_region): Drive clip to drawable.
-rw-r--r--ChangeLog29
-rw-r--r--configure.in14
-rw-r--r--src/cairo-features.h.in2
-rw-r--r--src/cairo-fixed.c11
-rw-r--r--src/cairo-gstate.c351
-rw-r--r--src/cairo-matrix.c24
-rw-r--r--src/cairo-xlib-surface.c52
-rw-r--r--src/cairo.c187
-rw-r--r--src/cairo_fixed.c11
-rw-r--r--src/cairo_gstate.c351
-rw-r--r--src/cairo_matrix.c24
-rw-r--r--src/cairo_xlib_surface.c52
-rw-r--r--src/cairoint.h9
13 files changed, 982 insertions, 135 deletions
diff --git a/ChangeLog b/ChangeLog
index fd6666982..a4414fbf7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,32 @@
+2004-05-20 Graydon Hoare <graydon@redhat.com>
+
+ * configure.in: Add sanity checking feature configury.
+
+ * src/cairo-features.h.in: Add sanity checking feature.
+
+ * src/cairo.c: Add sanity checking.
+
+ * src/cairoint.h: Add prototypes.
+
+ * src/cairo_fixed.c
+ (_cairo_fixed_is_integer):
+ (_cairo_fixed_integer_part): New functions.
+
+ * src/cairo_matrix.c
+ (_cairo_matrix_is_integer_translation): New function.
+
+ * src/cairo_gstate.c
+ (extract_transformed_rectangle): Use fixed functions.
+ (_cairo_gstate_clip): Arithmetic fixes.
+ (_cairo_gstate_clip_and_composite_trapezoids):
+ (_cairo_gstate_show_surface):
+ (_cairo_gstate_show_text):
+ (_cairo_gstate_show_glyphs): Corrections to clipping.
+
+ * src/cairo_xlib_surface.c
+ (_cairo_xlib_surface_composite): Add XCopyArea fast path.
+ (_cairo_xlib_surface_set_clip_region): Drive clip to drawable.
+
2004-05-17 Carl Worth <cworth@isi.edu>
* src/cairo.c (cairo_show_text): Do nothing when passed a NULL
diff --git a/configure.in b/configure.in
index 3ac8f8459..7b241b70a 100644
--- a/configure.in
+++ b/configure.in
@@ -161,6 +161,20 @@ AC_SUBST(GL_REQUIRES)
dnl ===========================================================================
+AC_ARG_ENABLE(sanity-checking,
+ [ --disable-sanity Disable cairo's sanity checking routines],
+ [check_sanity=$enableval], [check_sanity=yes])
+
+if test "x$check_sanity" != "xyes"; then
+ SANITY_CHECKING_FEATURE=CAIRO_NO_SANITY_CHECKING
+else
+ SANITY_CHECKING_FEATURE=CAIRO_DO_SANITY_CHECKING
+fi
+
+AC_SUBST(SANITY_CHECKING_FEATURE)
+
+dnl ===========================================================================
+
PKG_CHECK_MODULES(FONTCONFIG, fontconfig)
PKG_CHECK_MODULES(CAIRO, libpixman >= 0.1.1)
diff --git a/src/cairo-features.h.in b/src/cairo-features.h.in
index 7eec9780c..644f55ccc 100644
--- a/src/cairo-features.h.in
+++ b/src/cairo-features.h.in
@@ -38,4 +38,6 @@
#define @GL_SURFACE_FEATURE@
+#define @SANITY_CHECKING_FEATURE@
+
#endif
diff --git a/src/cairo-fixed.c b/src/cairo-fixed.c
index 9a7e7bc47..2561a4ad5 100644
--- a/src/cairo-fixed.c
+++ b/src/cairo-fixed.c
@@ -51,3 +51,14 @@ _cairo_fixed_to_double (cairo_fixed_t f)
return ((double) f) / 65536.0;
}
+int
+_cairo_fixed_is_integer (cairo_fixed_t f)
+{
+ return (f & 0xFFFF) == 0;
+}
+
+int
+_cairo_fixed_integer_part (cairo_fixed_t f)
+{
+ return f >> 16;
+}
diff --git a/src/cairo-gstate.c b/src/cairo-gstate.c
index ff3a2c659..7599d44cc 100644
--- a/src/cairo-gstate.c
+++ b/src/cairo-gstate.c
@@ -1435,12 +1435,15 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate,
if (status)
goto BAIL2;
+ if (dst == gstate->clip.surface)
+ xoff = yoff = 0;
+
status = _cairo_surface_composite (operator,
pattern.source, intermediate, dst,
0, 0,
0, 0,
- gstate->clip.x,
- gstate->clip.y,
+ xoff >> 16,
+ yoff >> 16,
gstate->clip.width,
gstate->clip.height);
@@ -1643,9 +1646,6 @@ extract_transformed_rectangle(cairo_matrix_t *mat,
cairo_traps_t *tr,
pixman_box16_t *box)
{
-#define CAIRO_FIXED_IS_INTEGER(x) (((x) & 0xFFFF) == 0)
-#define CAIRO_FIXED_INTEGER_PART(x) ((x) >> 16)
-
double a, b, c, d, tx, ty;
cairo_status_t st;
@@ -1658,25 +1658,22 @@ extract_transformed_rectangle(cairo_matrix_t *mat,
&& tr->traps[0].right.p1.x == tr->traps[0].right.p2.x
&& tr->traps[0].left.p1.y == tr->traps[0].right.p1.y
&& tr->traps[0].left.p2.y == tr->traps[0].right.p2.y
- && CAIRO_FIXED_IS_INTEGER(tr->traps[0].left.p1.x)
- && CAIRO_FIXED_IS_INTEGER(tr->traps[0].left.p1.y)
- && CAIRO_FIXED_IS_INTEGER(tr->traps[0].left.p2.x)
- && CAIRO_FIXED_IS_INTEGER(tr->traps[0].left.p2.y)
- && CAIRO_FIXED_IS_INTEGER(tr->traps[0].right.p1.x)
- && CAIRO_FIXED_IS_INTEGER(tr->traps[0].right.p1.y)
- && CAIRO_FIXED_IS_INTEGER(tr->traps[0].right.p2.x)
- && CAIRO_FIXED_IS_INTEGER(tr->traps[0].right.p2.y)) {
-
- box->x1 = (short) CAIRO_FIXED_INTEGER_PART(tr->traps[0].left.p1.x);
- box->x2 = (short) CAIRO_FIXED_INTEGER_PART(tr->traps[0].right.p1.x);
- box->y1 = (short) CAIRO_FIXED_INTEGER_PART(tr->traps[0].left.p1.y);
- box->y2 = (short) CAIRO_FIXED_INTEGER_PART(tr->traps[0].left.p2.y);
+ && _cairo_fixed_is_integer(tr->traps[0].left.p1.x)
+ && _cairo_fixed_is_integer(tr->traps[0].left.p1.y)
+ && _cairo_fixed_is_integer(tr->traps[0].left.p2.x)
+ && _cairo_fixed_is_integer(tr->traps[0].left.p2.y)
+ && _cairo_fixed_is_integer(tr->traps[0].right.p1.x)
+ && _cairo_fixed_is_integer(tr->traps[0].right.p1.y)
+ && _cairo_fixed_is_integer(tr->traps[0].right.p2.x)
+ && _cairo_fixed_is_integer(tr->traps[0].right.p2.y)) {
+
+ box->x1 = (short) _cairo_fixed_integer_part(tr->traps[0].left.p1.x);
+ box->x2 = (short) _cairo_fixed_integer_part(tr->traps[0].right.p1.x);
+ box->y1 = (short) _cairo_fixed_integer_part(tr->traps[0].left.p1.y);
+ box->y2 = (short) _cairo_fixed_integer_part(tr->traps[0].left.p2.y);
return 1;
}
return 0;
-
-#undef CAIRO_FIXED_IS_INTEGER
-#undef CAIRO_FIXED_INTEGER_PART
}
cairo_status_t
@@ -1743,20 +1740,20 @@ _cairo_gstate_clip (cairo_gstate_t *gstate)
_cairo_color_init (&white_color);
if (gstate->clip.surface == NULL) {
- double x1, y1, x2, y2;
- _cairo_path_bounds (&gstate->path,
- &x1, &y1, &x2, &y2);
- gstate->clip.x = floor (x1);
- gstate->clip.y = floor (y1);
- gstate->clip.width = ceil (x2 - gstate->clip.x);
- gstate->clip.height = ceil (y2 - gstate->clip.y);
- gstate->clip.surface =
- _cairo_surface_create_similar_solid (gstate->surface,
- CAIRO_FORMAT_A8,
- gstate->clip.width,
- gstate->clip.height,
- &white_color);
- if (gstate->clip.surface == NULL)
+ cairo_box_t extents;
+
+ _cairo_traps_extents (&traps, &extents);
+ gstate->clip.x = extents.p1.x >> 16;
+ gstate->clip.y = extents.p1.y >> 16;
+ gstate->clip.width = ((extents.p2.x + 65535) >> 16) - gstate->clip.x;
+ gstate->clip.height = ((extents.p2.y + 65535) >> 16) - gstate->clip.y;
+ gstate->clip.surface =
+ _cairo_surface_create_similar_solid (gstate->surface,
+ CAIRO_FORMAT_A8,
+ gstate->clip.width,
+ gstate->clip.height,
+ &white_color);
+ if (gstate->clip.surface == NULL)
return CAIRO_STATUS_NO_MEMORY;
}
@@ -1782,14 +1779,78 @@ _cairo_gstate_show_surface (cairo_gstate_t *gstate,
int width,
int height)
{
+
+ /* We are dealing with 5 coordinate spaces in this function. this makes
+ * it ugly.
+ *
+ * - "Image" space is the space of the surface we're reading pixels from.
+ * it is the surface argument to this function. The surface has a
+ * matrix attached to it which maps "user" space (see below) into
+ * image space.
+ *
+ * - "Device" space is the space of the surface we're ultimately writing
+ * pixels to. It is the current surface of the gstate argument to
+ * this function.
+ *
+ * - "User" space is an arbitrary space defined by the user, defined
+ * implicitly by the gstate's CTM. The CTM maps from user space to
+ * device space. The CTM inverse (which is also kept at all times)
+ * maps from device space to user space.
+ *
+ * - "Clip" space is the space of the surface being used to clip pixels
+ * during compositing. Space-wise, it is a bounding box (offset+size)
+ * within device space. This surface is usually smaller than the device
+ * surface (and possibly the image surface too) and logically occupies
+ * a bounding box around the "clip path", situated somewhere in device
+ * space. The clip path is already painted on the clip surface.
+ *
+ * - "Pattern" space is another arbitrary space defined in the pattern
+ * element of gstate. As pixels are read from image space, they are
+ * combined with pixels being read from pattern space and pixels
+ * already existing in device space. User coordinates are converted
+ * to pattern space, similarly, using a matrix attached to the pattern.
+ * (in fact, there is a 6th space in here, which is the space of the
+ * surface acting as a source for the pattern)
+ *
+ * To composite these spaces, we temporarily change the image surface
+ * so that it can be read and written in device coordinates; in a sense
+ * this makes it "spatially compatible" with the clip and device spaces.
+ *
+ *
+ * There is also some confusion about the interaction between a clip and
+ * a pattern; it is assumed that in this "show surface" operation a pattern
+ * is to be used as an auxiliary alpha mask. this might be wrong, but it's
+ * what we're doing now.
+ *
+ * so, to follow the operations below, remember that in the compositing
+ * model, each operation is always of the form ((src IN mask) OP dst).
+ * that's the basic operation.
+ *
+ * so the compositing we are trying to do here, in general, involves 2
+ * steps, going via a temporary surface:
+ *
+ * - combining clip and pattern pixels together into a mask channel.
+ * this will be ((pattern IN clip) SRC temporary). it ignores the
+ * pixels already in the temporary, overwriting it with the
+ * pattern, clipped to the clip mask.
+ *
+ * - combining temporary and "image" pixels with "device" pixels,
+ * with a user-provided porter/duff operator. this will be
+ * ((image IN temporary) OP device).
+ *
+ * if there is no clip, the degenerate case is just the second step
+ * with pattern standing in for temporary.
+ *
+ */
+
cairo_status_t status;
cairo_matrix_t user_to_image, image_to_user;
cairo_matrix_t image_to_device, device_to_image;
double device_x, device_y;
double device_width, device_height;
cairo_pattern_t pattern;
- cairo_box_t extents;
-
+ cairo_box_t pattern_extents;
+
cairo_surface_get_matrix (surface, &user_to_image);
cairo_matrix_multiply (&device_to_image, &gstate->ctm_inverse, &user_to_image);
cairo_surface_set_matrix (surface, &device_to_image);
@@ -1808,31 +1869,84 @@ _cairo_gstate_show_surface (cairo_gstate_t *gstate,
_cairo_pattern_init (&pattern);
if ((gstate->pattern->type != CAIRO_PATTERN_SOLID) ||
- (gstate->alpha != 1.0)) {
+ (gstate->alpha != 1.0)) {
/* I'm allowing any type of pattern for the mask right now.
Maybe this is bad. Will allow for some cool effects though. */
_cairo_pattern_init_copy (&pattern, gstate->pattern);
- extents.p1.x = _cairo_fixed_from_double (device_x);
- extents.p1.y = _cairo_fixed_from_double (device_y);
- extents.p2.x = _cairo_fixed_from_double (device_x + device_width);
- extents.p2.y = _cairo_fixed_from_double (device_y + device_height);
- status = _cairo_gstate_create_pattern (gstate, &pattern, &extents);
+ pattern_extents.p1.x = _cairo_fixed_from_double (device_x);
+ pattern_extents.p1.y = _cairo_fixed_from_double (device_y);
+ pattern_extents.p2.x = _cairo_fixed_from_double (device_x + device_width);
+ pattern_extents.p2.y = _cairo_fixed_from_double (device_y + device_height);
+ status = _cairo_gstate_create_pattern (gstate, &pattern, &pattern_extents);
if (status)
return status;
}
- /* XXX: The rendered size is sometimes 1 or 2 pixels short from
- what I expect. Need to fix this. */
- status = _cairo_surface_composite (gstate->operator,
- surface, pattern.source, gstate->surface,
- device_x, device_y,
- 0, 0,
- device_x, device_y,
- device_width,
- device_height);
+ if (gstate->clip.surface)
+ {
+ cairo_surface_t *intermediate;
+ cairo_color_t empty_color;
- _cairo_pattern_fini (&pattern);
+ _cairo_color_init (&empty_color);
+ _cairo_color_set_alpha (&empty_color, .0);
+ intermediate = _cairo_surface_create_similar_solid (gstate->clip.surface,
+ CAIRO_FORMAT_A8,
+ gstate->clip.width,
+ gstate->clip.height,
+ &empty_color);
+
+ /* it is not completely clear what the "right" way to combine the
+ pattern and mask surface is. I will use the the clip as a source
+ and the pattern as a mask in building up my temporary, because
+ this is not *totally* bogus and accomodates the case where
+ pattern's source image is NULL reasonably well. feel free to
+ correct this if you see a reason. */
+
+ status = _cairo_surface_composite (CAIRO_OPERATOR_SRC,
+ gstate->clip.surface,
+ pattern.source,
+ intermediate,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ gstate->clip.width,
+ gstate->clip.height);
+
+ if (status)
+ goto BAIL;
+
+ status = _cairo_surface_composite (gstate->operator,
+ surface,
+ intermediate,
+ gstate->surface,
+ gstate->clip.x, gstate->clip.y,
+ 0, 0,
+ gstate->clip.x, gstate->clip.y,
+ gstate->clip.width,
+ gstate->clip.height);
+
+ BAIL:
+ cairo_surface_destroy (intermediate);
+ }
+ else
+ {
+
+ /* XXX: The rendered size is sometimes 1 or 2 pixels short from
+ what I expect. Need to fix this. */
+ status = _cairo_surface_composite (gstate->operator,
+ surface,
+ pattern.source,
+ gstate->surface,
+ device_x, device_y,
+ 0, 0,
+ device_x, device_y,
+ device_width,
+ device_height);
+
+ }
+ _cairo_pattern_fini (&pattern);
+
/* restore the matrix originally in the surface */
cairo_surface_set_matrix (surface, &user_to_image);
@@ -2004,10 +2118,62 @@ _cairo_gstate_show_text (cairo_gstate_t *gstate,
status = _cairo_gstate_create_pattern (gstate, &pattern, &extents);
if (status)
return status;
-
- status = _cairo_font_show_text (gstate->font,
- gstate->operator, pattern.source,
- gstate->surface, x, y, utf8);
+ if (gstate->clip.surface)
+ {
+ cairo_surface_t *intermediate;
+ cairo_color_t empty_color;
+
+ _cairo_color_init (&empty_color);
+ _cairo_color_set_alpha (&empty_color, .0);
+ intermediate = _cairo_surface_create_similar_solid (gstate->clip.surface,
+ CAIRO_FORMAT_A8,
+ gstate->clip.width,
+ gstate->clip.height,
+ &empty_color);
+
+ status = _cairo_font_show_text (gstate->font,
+ CAIRO_OPERATOR_ADD, pattern.source,
+ intermediate,
+ x - gstate->clip.x,
+ y - gstate->clip.y, utf8);
+
+ if (status)
+ goto BAIL;
+
+ status = _cairo_surface_composite (CAIRO_OPERATOR_IN,
+ gstate->clip.surface,
+ NULL,
+ intermediate,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ gstate->clip.width,
+ gstate->clip.height);
+
+ if (status)
+ goto BAIL;
+
+ status = _cairo_surface_composite (gstate->operator,
+ pattern.source,
+ intermediate,
+ gstate->surface,
+ 0, 0,
+ 0, 0,
+ gstate->clip.x,
+ gstate->clip.y,
+ gstate->clip.width,
+ gstate->clip.height);
+
+ BAIL:
+ cairo_surface_destroy (intermediate);
+
+ }
+ else
+ {
+ status = _cairo_font_show_text (gstate->font,
+ gstate->operator, pattern.source,
+ gstate->surface, x, y, utf8);
+ }
cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix);
@@ -2045,8 +2211,8 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
cairo_matrix_multiply (&gstate->font->matrix, &gstate->ctm, &gstate->font->matrix);
_cairo_pattern_init_copy (&pattern, gstate->pattern);
- _cairo_gstate_glyph_extents (gstate, transformed_glyphs, num_glyphs,
- &text_extents);
+ status = _cairo_gstate_glyph_extents (gstate, transformed_glyphs, num_glyphs,
+ &text_extents);
if (status)
return status;
@@ -2059,11 +2225,70 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
status = _cairo_gstate_create_pattern (gstate, &pattern, &extents);
if (status)
return status;
+
+ if (gstate->clip.surface)
+ {
+ cairo_surface_t *intermediate;
+ cairo_color_t empty_color;
+
+ _cairo_color_init (&empty_color);
+ _cairo_color_set_alpha (&empty_color, .0);
+ intermediate = _cairo_surface_create_similar_solid (gstate->clip.surface,
+ CAIRO_FORMAT_A8,
+ gstate->clip.width,
+ gstate->clip.height,
+ &empty_color);
+
+ /* move the glyphs again, from dev space to clip space */
+ for (i = 0; i < num_glyphs; ++i)
+ {
+ transformed_glyphs[i].x -= gstate->clip.x;
+ transformed_glyphs[i].y -= gstate->clip.y;
+ }
+
+ status = _cairo_font_show_glyphs (gstate->font,
+ CAIRO_OPERATOR_ADD,
+ pattern.source, intermediate,
+ transformed_glyphs, num_glyphs);
+
+ if (status)
+ goto BAIL;
- status = _cairo_font_show_glyphs (gstate->font,
- gstate->operator, pattern.source,
- gstate->surface,
- transformed_glyphs, num_glyphs);
+ status = _cairo_surface_composite (CAIRO_OPERATOR_IN,
+ gstate->clip.surface,
+ NULL,
+ intermediate,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ gstate->clip.width,
+ gstate->clip.height);
+
+ if (status)
+ goto BAIL;
+
+ status = _cairo_surface_composite (gstate->operator,
+ pattern.source,
+ intermediate,
+ gstate->surface,
+ 0, 0,
+ 0, 0,
+ gstate->clip.x,
+ gstate->clip.y,
+ gstate->clip.width,
+ gstate->clip.height);
+
+ BAIL:
+ cairo_surface_destroy (intermediate);
+
+ }
+ else
+ {
+ status = _cairo_font_show_glyphs (gstate->font,
+ gstate->operator, pattern.source,
+ gstate->surface,
+ transformed_glyphs, num_glyphs);
+ }
cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix);
diff --git a/src/cairo-matrix.c b/src/cairo-matrix.c
index de89c0fd5..cc5635fff 100644
--- a/src/cairo-matrix.c
+++ b/src/cairo-matrix.c
@@ -405,3 +405,27 @@ _cairo_matrix_compute_scale_factors (cairo_matrix_t *matrix, double *sx, double
return CAIRO_STATUS_SUCCESS;
}
+
+int
+_cairo_matrix_is_integer_translation(cairo_matrix_t *mat,
+ int *itx, int *ity)
+{
+ double a, b, c, d, tx, ty;
+ int ttx, tty;
+ int ok = 0;
+ cairo_matrix_get_affine (mat, &a, &b, &c, &d, &tx, &ty);
+ ttx = _cairo_fixed_from_double (tx);
+ tty = _cairo_fixed_from_double (ty);
+ ok = ((a == 1.0)
+ && (b == 0.0)
+ && (c == 0.0)
+ && (d == 1.0)
+ && (_cairo_fixed_is_integer(ttx))
+ && (_cairo_fixed_is_integer(tty)));
+ if (ok) {
+ *itx = _cairo_fixed_integer_part(ttx);
+ *ity = _cairo_fixed_integer_part(tty);
+ return 1;
+ }
+ return 0;
+}
diff --git a/src/cairo-xlib-surface.c b/src/cairo-xlib-surface.c
index 19dfde503..b54284aa2 100644
--- a/src/cairo-xlib-surface.c
+++ b/src/cairo-xlib-surface.c
@@ -455,7 +455,8 @@ _cairo_xlib_surface_composite (cairo_operator_t operator,
cairo_xlib_surface_t *mask = (cairo_xlib_surface_t *) generic_mask;
cairo_xlib_surface_t *src_clone = NULL;
cairo_xlib_surface_t *mask_clone = NULL;
-
+ XGCValues gc_values;
+ int src_x_off, src_y_off, dst_x_off, dst_y_off;
if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (dst))
return CAIRO_INT_STATUS_UNSUPPORTED;
@@ -475,6 +476,28 @@ _cairo_xlib_surface_composite (cairo_operator_t operator,
mask = mask_clone;
}
+ if (operator == CAIRO_OPERATOR_SRC
+ && !mask
+ && _cairo_matrix_is_integer_translation(&(src->base.matrix),
+ &src_x_off, &src_y_off)
+ && _cairo_matrix_is_integer_translation(&(dst->base.matrix),
+ &dst_x_off, &dst_y_off)) {
+ /* Fast path for copying "raw" areas. */
+ _cairo_xlib_surface_ensure_gc (dst);
+ XGetGCValues(dst->dpy, dst->gc, GCGraphicsExposures, &gc_values);
+ XSetGraphicsExposures(dst->dpy, dst->gc, False);
+ XCopyArea(dst->dpy,
+ src->drawable,
+ dst->drawable,
+ dst->gc,
+ src_x + src_x_off,
+ src_y + src_y_off,
+ width, height,
+ dst_x + dst_x_off,
+ dst_y + dst_y_off);
+ XSetGraphicsExposures(dst->dpy, dst->gc, gc_values.graphics_exposures);
+
+ } else {
XRenderComposite (dst->dpy,
_render_operator (operator),
src->picture,
@@ -484,6 +507,7 @@ _cairo_xlib_surface_composite (cairo_operator_t operator,
mask_x, mask_y,
dst_x, dst_y,
width, height);
+ }
/* XXX: This is messed up. If I can xlib_surface_create, then I
should be able to xlib_surface_destroy. */
@@ -577,8 +601,11 @@ static cairo_int_status_t
_cairo_xlib_surface_set_clip_region (void *abstract_surface,
pixman_region16_t *region)
{
+
Region xregion;
XRectangle xr;
+ XRectangle *rects = NULL;
+ XGCValues gc_values;
pixman_box16_t *box;
cairo_xlib_surface_t *surf;
int n, m;
@@ -593,13 +620,17 @@ _cairo_xlib_surface_set_clip_region (void *abstract_surface,
xr.width = surf->width;
xr.height = surf->height;
XUnionRectWithRegion (&xr, xregion, xregion);
+ rects = malloc(sizeof(XRectangle));
+ rects[0] = xr;
+ m = 1;
+
} else {
n = pixman_region_num_rects (region);
/* XXX: Are we sure these are the semantics we want for an
* empty, (not null) region? */
if (n == 0)
return CAIRO_STATUS_SUCCESS;
-
+ rects = malloc(sizeof(XRectangle) * n);
box = pixman_region_rects (region);
xregion = XCreateRegion();
@@ -609,13 +640,20 @@ _cairo_xlib_surface_set_clip_region (void *abstract_surface,
xr.y = (short) box->y1;
xr.width = (unsigned short) (box->x2 - box->x1);
xr.height = (unsigned short) (box->y2 - box->y1);
+ rects[n-1] = xr;
XUnionRectWithRegion (&xr, xregion, xregion);
}
}
+ _cairo_xlib_surface_ensure_gc (surf);
+ XGetGCValues(surf->dpy, surf->gc, GCGraphicsExposures, &gc_values);
+ XSetGraphicsExposures(surf->dpy, surf->gc, False);
+ XSetClipRectangles(surf->dpy, surf->gc, 0, 0, rects, m, Unsorted);
+ free(rects);
+ if (surf->picture)
XRenderSetPictureClipRegion (surf->dpy, surf->picture, xregion);
XDestroyRegion(xregion);
-
+ XSetGraphicsExposures(surf->dpy, surf->gc, gc_values.graphics_exposures);
return CAIRO_STATUS_SUCCESS;
}
@@ -654,6 +692,8 @@ cairo_xlib_surface_create (Display *dpy,
{
cairo_xlib_surface_t *surface;
int render_standard;
+ Window w;
+ unsigned int ignore;
surface = malloc (sizeof (cairo_xlib_surface_t));
if (surface == NULL)
@@ -692,6 +732,12 @@ cairo_xlib_surface_create (Display *dpy,
break;
}
+ XGetGeometry(dpy, drawable,
+ &w, &ignore, &ignore,
+ &surface->width,
+ &surface->height,
+ &ignore, &ignore);
+
/* XXX: I'm currently ignoring the colormap. Is that bad? */
if (CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE (surface))
surface->picture = XRenderCreatePicture (dpy, drawable,
diff --git a/src/cairo.c b/src/cairo.c
index 0c35448f6..d09aa0520 100644
--- a/src/cairo.c
+++ b/src/cairo.c
@@ -29,6 +29,34 @@
#define CAIRO_TOLERANCE_MINIMUM 0.0002 /* We're limited by 16 bits of sub-pixel precision */
+
+#ifdef CAIRO_DO_SANITY_CHECKING
+#include <assert.h>
+static int
+cairo_sane_state (cairo_t *cr)
+{
+ switch (cr->status) {
+ case CAIRO_STATUS_SUCCESS:
+ case CAIRO_STATUS_NO_MEMORY:
+ case CAIRO_STATUS_INVALID_RESTORE:
+ case CAIRO_STATUS_INVALID_POP_GROUP:
+ case CAIRO_STATUS_NO_CURRENT_POINT:
+ case CAIRO_STATUS_INVALID_MATRIX:
+ case CAIRO_STATUS_NO_TARGET_SURFACE:
+ case CAIRO_STATUS_NULL_POINTER:
+ break;
+ default:
+ printf ("cairo status is bad: %d\n", cr->status);
+ return 0;
+ }
+ return 1;
+}
+#define CAIRO_CHECK_SANITY(cr) assert(cairo_sane_state ((cr)));
+#else
+#define CAIRO_CHECK_SANITY(cr)
+#endif
+
+
cairo_t *
cairo_create (void)
{
@@ -45,21 +73,25 @@ cairo_create (void)
if (cr->gstate == NULL)
cr->status = CAIRO_STATUS_NO_MEMORY;
+ CAIRO_CHECK_SANITY (cr);
return cr;
}
void
cairo_reference (cairo_t *cr)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->ref_count++;
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_destroy (cairo_t *cr)
{
+ CAIRO_CHECK_SANITY (cr);
cr->ref_count--;
if (cr->ref_count)
return;
@@ -79,6 +111,7 @@ cairo_save (cairo_t *cr)
{
cairo_gstate_t *top;
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
@@ -90,17 +123,20 @@ cairo_save (cairo_t *cr)
if (top == NULL) {
cr->status = CAIRO_STATUS_NO_MEMORY;
+ CAIRO_CHECK_SANITY (cr);
return;
}
top->next = cr->gstate;
cr->gstate = top;
+ CAIRO_CHECK_SANITY (cr);
}
slim_hidden_def(cairo_save);
void
cairo_restore (cairo_t *cr)
{
+ CAIRO_CHECK_SANITY (cr);
cairo_gstate_t *top;
if (cr->status)
@@ -113,12 +149,15 @@ cairo_restore (cairo_t *cr)
if (cr->gstate == NULL)
cr->status = CAIRO_STATUS_INVALID_RESTORE;
+ CAIRO_CHECK_SANITY (cr);
}
slim_hidden_def(cairo_restore);
void
cairo_copy (cairo_t *dest, cairo_t *src)
{
+ CAIRO_CHECK_SANITY (src);
+ CAIRO_CHECK_SANITY (dest);
if (dest->status)
return;
@@ -128,6 +167,8 @@ cairo_copy (cairo_t *dest, cairo_t *src)
}
dest->status = _cairo_gstate_copy (dest->gstate, src->gstate);
+ CAIRO_CHECK_SANITY (src);
+ CAIRO_CHECK_SANITY (dest);
}
/* XXX: I want to rethink this API
@@ -161,10 +202,12 @@ cairo_pop_group (cairo_t *cr)
void
cairo_set_target_surface (cairo_t *cr, cairo_surface_t *surface)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_set_target_surface (cr->gstate, surface);
+ CAIRO_CHECK_SANITY (cr);
}
slim_hidden_def(cairo_set_target_surface);
@@ -178,6 +221,7 @@ cairo_set_target_image (cairo_t *cr,
{
cairo_surface_t *surface;
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
@@ -186,26 +230,31 @@ cairo_set_target_image (cairo_t *cr,
width, height, stride);
if (surface == NULL) {
cr->status = CAIRO_STATUS_NO_MEMORY;
+ CAIRO_CHECK_SANITY (cr);
return;
}
cairo_set_target_surface (cr, surface);
cairo_surface_destroy (surface);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_set_operator (cairo_t *cr, cairo_operator_t op)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_set_operator (cr->gstate, op);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_set_rgb_color (cairo_t *cr, double red, double green, double blue)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
@@ -214,228 +263,276 @@ cairo_set_rgb_color (cairo_t *cr, double red, double green, double blue)
_cairo_restrict_value (&blue, 0.0, 1.0);
cr->status = _cairo_gstate_set_rgb_color (cr->gstate, red, green, blue);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_set_pattern (cairo_t *cr, cairo_pattern_t *pattern)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_set_pattern (cr->gstate, pattern);
+ CAIRO_CHECK_SANITY (cr);
}
cairo_pattern_t *
cairo_current_pattern (cairo_t *cr)
{
+ CAIRO_CHECK_SANITY (cr);
return _cairo_gstate_current_pattern (cr->gstate);
}
void
cairo_set_tolerance (cairo_t *cr, double tolerance)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
_cairo_restrict_value (&tolerance, CAIRO_TOLERANCE_MINIMUM, tolerance);
cr->status = _cairo_gstate_set_tolerance (cr->gstate, tolerance);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_set_alpha (cairo_t *cr, double alpha)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
_cairo_restrict_value (&alpha, 0.0, 1.0);
cr->status = _cairo_gstate_set_alpha (cr->gstate, alpha);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_set_fill_rule (cairo_t *cr, cairo_fill_rule_t fill_rule)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_set_fill_rule (cr->gstate, fill_rule);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_set_line_width (cairo_t *cr, double width)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
_cairo_restrict_value (&width, 0.0, width);
cr->status = _cairo_gstate_set_line_width (cr->gstate, width);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_set_line_cap (cairo_t *cr, cairo_line_cap_t line_cap)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_set_line_cap (cr->gstate, line_cap);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_set_line_join (cairo_t *cr, cairo_line_join_t line_join)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_set_line_join (cr->gstate, line_join);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_set_dash (cairo_t *cr, double *dashes, int ndash, double offset)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_set_dash (cr->gstate, dashes, ndash, offset);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_set_miter_limit (cairo_t *cr, double limit)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_set_miter_limit (cr->gstate, limit);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_translate (cairo_t *cr, double tx, double ty)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_translate (cr->gstate, tx, ty);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_scale (cairo_t *cr, double sx, double sy)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_scale (cr->gstate, sx, sy);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_rotate (cairo_t *cr, double angle)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_rotate (cr->gstate, angle);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_concat_matrix (cairo_t *cr,
cairo_matrix_t *matrix)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_concat_matrix (cr->gstate, matrix);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_set_matrix (cairo_t *cr,
cairo_matrix_t *matrix)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_set_matrix (cr->gstate, matrix);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_default_matrix (cairo_t *cr)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_default_matrix (cr->gstate);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_identity_matrix (cairo_t *cr)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_identity_matrix (cr->gstate);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_transform_point (cairo_t *cr, double *x, double *y)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_transform_point (cr->gstate, x, y);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_transform_distance (cairo_t *cr, double *dx, double *dy)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_transform_distance (cr->gstate, dx, dy);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_inverse_transform_point (cairo_t *cr, double *x, double *y)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_inverse_transform_point (cr->gstate, x, y);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_inverse_transform_distance (cairo_t *cr, double *dx, double *dy)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_inverse_transform_distance (cr->gstate, dx, dy);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_new_path (cairo_t *cr)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_new_path (cr->gstate);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_move_to (cairo_t *cr, double x, double y)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_move_to (cr->gstate, x, y);
+ CAIRO_CHECK_SANITY (cr);
}
slim_hidden_def(cairo_move_to);
void
cairo_line_to (cairo_t *cr, double x, double y)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_line_to (cr->gstate, x, y);
+ CAIRO_CHECK_SANITY (cr);
}
void
@@ -444,6 +541,7 @@ cairo_curve_to (cairo_t *cr,
double x2, double y2,
double x3, double y3)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
@@ -451,6 +549,7 @@ cairo_curve_to (cairo_t *cr,
x1, y1,
x2, y2,
x3, y3);
+ CAIRO_CHECK_SANITY (cr);
}
void
@@ -459,6 +558,7 @@ cairo_arc (cairo_t *cr,
double radius,
double angle1, double angle2)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
@@ -466,6 +566,7 @@ cairo_arc (cairo_t *cr,
xc, yc,
radius,
angle1, angle2);
+ CAIRO_CHECK_SANITY (cr);
}
void
@@ -474,6 +575,7 @@ cairo_arc_negative (cairo_t *cr,
double radius,
double angle1, double angle2)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
@@ -481,6 +583,7 @@ cairo_arc_negative (cairo_t *cr,
xc, yc,
radius,
angle1, angle2);
+ CAIRO_CHECK_SANITY (cr);
}
/* XXX: NYI
@@ -503,19 +606,23 @@ cairo_arc_to (cairo_t *cr,
void
cairo_rel_move_to (cairo_t *cr, double dx, double dy)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_rel_move_to (cr->gstate, dx, dy);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_rel_line_to (cairo_t *cr, double dx, double dy)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_rel_line_to (cr->gstate, dx, dy);
+ CAIRO_CHECK_SANITY (cr);
}
slim_hidden_def(cairo_rel_line_to);
@@ -525,6 +632,7 @@ cairo_rel_curve_to (cairo_t *cr,
double dx2, double dy2,
double dx3, double dy3)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
@@ -532,6 +640,7 @@ cairo_rel_curve_to (cairo_t *cr,
dx1, dy1,
dx2, dy2,
dx3, dy3);
+ CAIRO_CHECK_SANITY (cr);
}
void
@@ -539,6 +648,7 @@ cairo_rectangle (cairo_t *cr,
double x, double y,
double width, double height)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
@@ -547,6 +657,7 @@ cairo_rectangle (cairo_t *cr,
cairo_rel_line_to (cr, 0, height);
cairo_rel_line_to (cr, -width, 0);
cairo_close_path (cr);
+ CAIRO_CHECK_SANITY (cr);
}
/* XXX: NYI
@@ -563,47 +674,57 @@ cairo_stroke_path (cairo_t *cr)
void
cairo_close_path (cairo_t *cr)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_close_path (cr->gstate);
+ CAIRO_CHECK_SANITY (cr);
}
slim_hidden_def(cairo_close_path);
void
cairo_stroke (cairo_t *cr)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_stroke (cr->gstate);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_fill (cairo_t *cr)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_fill (cr->gstate);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_copy_page (cairo_t *cr)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_copy_page (cr->gstate);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_show_page (cairo_t *cr)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_show_page (cr->gstate);
+ CAIRO_CHECK_SANITY (cr);
}
int
@@ -611,11 +732,14 @@ cairo_in_stroke (cairo_t *cr, double x, double y)
{
int inside;
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return 0;
cr->status = _cairo_gstate_in_stroke (cr->gstate, x, y, &inside);
+ CAIRO_CHECK_SANITY (cr);
+
if (cr->status)
return 0;
@@ -627,11 +751,14 @@ cairo_in_fill (cairo_t *cr, double x, double y)
{
int inside;
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return 0;
cr->status = _cairo_gstate_in_fill (cr->gstate, x, y, &inside);
+ CAIRO_CHECK_SANITY (cr);
+
if (cr->status)
return 0;
@@ -642,38 +769,46 @@ void
cairo_stroke_extents (cairo_t *cr,
double *x1, double *y1, double *x2, double *y2)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_stroke_extents (cr->gstate, x1, y1, x2, y2);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_fill_extents (cairo_t *cr,
double *x1, double *y1, double *x2, double *y2)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_fill_extents (cr->gstate, x1, y1, x2, y2);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_init_clip (cairo_t *cr)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_init_clip (cr->gstate);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_clip (cairo_t *cr)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_clip (cr->gstate);
+ CAIRO_CHECK_SANITY (cr);
}
void
@@ -682,60 +817,72 @@ cairo_select_font (cairo_t *cr,
cairo_font_slant_t slant,
cairo_font_weight_t weight)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_select_font (cr->gstate, family, slant, weight);
+ CAIRO_CHECK_SANITY (cr);
}
cairo_font_t *
cairo_current_font (cairo_t *cr)
{
+ CAIRO_CHECK_SANITY (cr);
cairo_font_t *ret;
if (cr->status)
return NULL;
cr->status = _cairo_gstate_current_font (cr->gstate, &ret);
+ CAIRO_CHECK_SANITY (cr);
return ret;
}
void
-cairo_current_font_extents (cairo_t *ct,
+cairo_current_font_extents (cairo_t *cr,
cairo_font_extents_t *extents)
{
- if (ct->status)
+ CAIRO_CHECK_SANITY (cr);
+ if (cr->status)
return;
- ct->status = _cairo_gstate_current_font_extents (ct->gstate, extents);
+ cr->status = _cairo_gstate_current_font_extents (cr->gstate, extents);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_set_font (cairo_t *cr, cairo_font_t *font)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_set_font (cr->gstate, font);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_scale_font (cairo_t *cr, double scale)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_scale_font (cr->gstate, scale);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_transform_font (cairo_t *cr, cairo_matrix_t *matrix)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_transform_font (cr->gstate, matrix);
+ CAIRO_CHECK_SANITY (cr);
}
void
@@ -743,10 +890,12 @@ cairo_text_extents (cairo_t *cr,
const unsigned char *utf8,
cairo_text_extents_t *extents)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_text_extents (cr->gstate, utf8, extents);
+ CAIRO_CHECK_SANITY (cr);
}
void
@@ -755,16 +904,19 @@ cairo_glyph_extents (cairo_t *cr,
int num_glyphs,
cairo_text_extents_t *extents)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_glyph_extents (cr->gstate, glyphs, num_glyphs,
extents);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_show_text (cairo_t *cr, const unsigned char *utf8)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
@@ -772,33 +924,40 @@ cairo_show_text (cairo_t *cr, const unsigned char *utf8)
return;
cr->status = _cairo_gstate_show_text (cr->gstate, utf8);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_show_glyphs (cairo_t *cr, cairo_glyph_t *glyphs, int num_glyphs)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_show_glyphs (cr->gstate, glyphs, num_glyphs);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_text_path (cairo_t *cr, const unsigned char *utf8)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_text_path (cr->gstate, utf8);
+ CAIRO_CHECK_SANITY (cr);
}
void
cairo_glyph_path (cairo_t *cr, cairo_glyph_t *glyphs, int num_glyphs)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_glyph_path (cr->gstate, glyphs, num_glyphs);
+ CAIRO_CHECK_SANITY (cr);
}
void
@@ -807,16 +966,19 @@ cairo_show_surface (cairo_t *cr,
int width,
int height)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
cr->status = _cairo_gstate_show_surface (cr->gstate,
surface, width, height);
+ CAIRO_CHECK_SANITY (cr);
}
cairo_operator_t
cairo_current_operator (cairo_t *cr)
{
+ CAIRO_CHECK_SANITY (cr);
return _cairo_gstate_current_operator (cr->gstate);
}
DEPRECATE (cairo_get_operator, cairo_current_operator);
@@ -824,13 +986,16 @@ DEPRECATE (cairo_get_operator, cairo_current_operator);
void
cairo_current_rgb_color (cairo_t *cr, double *red, double *green, double *blue)
{
+ CAIRO_CHECK_SANITY (cr);
_cairo_gstate_current_rgb_color (cr->gstate, red, green, blue);
+ CAIRO_CHECK_SANITY (cr);
}
DEPRECATE (cairo_get_rgb_color, cairo_current_rgb_color);
double
cairo_current_alpha (cairo_t *cr)
{
+ CAIRO_CHECK_SANITY (cr);
return _cairo_gstate_current_alpha (cr->gstate);
}
DEPRECATE (cairo_get_alpha, cairo_current_alpha);
@@ -838,6 +1003,7 @@ DEPRECATE (cairo_get_alpha, cairo_current_alpha);
double
cairo_current_tolerance (cairo_t *cr)
{
+ CAIRO_CHECK_SANITY (cr);
return _cairo_gstate_current_tolerance (cr->gstate);
}
DEPRECATE (cairo_get_tolerance, cairo_current_tolerance);
@@ -845,13 +1011,16 @@ DEPRECATE (cairo_get_tolerance, cairo_current_tolerance);
void
cairo_current_point (cairo_t *cr, double *x, double *y)
{
+ CAIRO_CHECK_SANITY (cr);
_cairo_gstate_current_point (cr->gstate, x, y);
+ CAIRO_CHECK_SANITY (cr);
}
DEPRECATE (cairo_get_current_point, cairo_current_point);
cairo_fill_rule_t
cairo_current_fill_rule (cairo_t *cr)
{
+ CAIRO_CHECK_SANITY (cr);
return _cairo_gstate_current_fill_rule (cr->gstate);
}
DEPRECATE (cairo_get_fill_rule, cairo_current_fill_rule);
@@ -859,6 +1028,7 @@ DEPRECATE (cairo_get_fill_rule, cairo_current_fill_rule);
double
cairo_current_line_width (cairo_t *cr)
{
+ CAIRO_CHECK_SANITY (cr);
return _cairo_gstate_current_line_width (cr->gstate);
}
DEPRECATE (cairo_get_line_width, cairo_current_line_width);
@@ -866,6 +1036,7 @@ DEPRECATE (cairo_get_line_width, cairo_current_line_width);
cairo_line_cap_t
cairo_current_line_cap (cairo_t *cr)
{
+ CAIRO_CHECK_SANITY (cr);
return _cairo_gstate_current_line_cap (cr->gstate);
}
DEPRECATE (cairo_get_line_cap, cairo_current_line_cap);
@@ -873,6 +1044,7 @@ DEPRECATE (cairo_get_line_cap, cairo_current_line_cap);
cairo_line_join_t
cairo_current_line_join (cairo_t *cr)
{
+ CAIRO_CHECK_SANITY (cr);
return _cairo_gstate_current_line_join (cr->gstate);
}
DEPRECATE (cairo_get_line_join, cairo_current_line_join);
@@ -880,6 +1052,7 @@ DEPRECATE (cairo_get_line_join, cairo_current_line_join);
double
cairo_current_miter_limit (cairo_t *cr)
{
+ CAIRO_CHECK_SANITY (cr);
return _cairo_gstate_current_miter_limit (cr->gstate);
}
DEPRECATE (cairo_get_miter_limit, cairo_current_miter_limit);
@@ -887,13 +1060,16 @@ DEPRECATE (cairo_get_miter_limit, cairo_current_miter_limit);
void
cairo_current_matrix (cairo_t *cr, cairo_matrix_t *matrix)
{
+ CAIRO_CHECK_SANITY (cr);
_cairo_gstate_current_matrix (cr->gstate, matrix);
+ CAIRO_CHECK_SANITY (cr);
}
DEPRECATE (cairo_get_matrix, cairo_current_matrix);
cairo_surface_t *
cairo_current_target_surface (cairo_t *cr)
{
+ CAIRO_CHECK_SANITY (cr);
return _cairo_gstate_current_target_surface (cr->gstate);
}
DEPRECATE (cairo_get_target_surface, cairo_current_target_surface);
@@ -906,6 +1082,7 @@ cairo_current_path (cairo_t *cr,
cairo_close_path_func_t *close_path,
void *closure)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
@@ -915,6 +1092,7 @@ cairo_current_path (cairo_t *cr,
curve_to,
close_path,
closure);
+ CAIRO_CHECK_SANITY (cr);
}
void
@@ -924,6 +1102,7 @@ cairo_current_path_flat (cairo_t *cr,
cairo_close_path_func_t *close_path,
void *closure)
{
+ CAIRO_CHECK_SANITY (cr);
if (cr->status)
return;
@@ -933,11 +1112,13 @@ cairo_current_path_flat (cairo_t *cr,
NULL,
close_path,
closure);
+ CAIRO_CHECK_SANITY (cr);
}
cairo_status_t
cairo_status (cairo_t *cr)
{
+ CAIRO_CHECK_SANITY (cr);
return cr->status;
}
DEPRECATE (cairo_get_status, cairo_status);
diff --git a/src/cairo_fixed.c b/src/cairo_fixed.c
index 9a7e7bc47..2561a4ad5 100644
--- a/src/cairo_fixed.c
+++ b/src/cairo_fixed.c
@@ -51,3 +51,14 @@ _cairo_fixed_to_double (cairo_fixed_t f)
return ((double) f) / 65536.0;
}
+int
+_cairo_fixed_is_integer (cairo_fixed_t f)
+{
+ return (f & 0xFFFF) == 0;
+}
+
+int
+_cairo_fixed_integer_part (cairo_fixed_t f)
+{
+ return f >> 16;
+}
diff --git a/src/cairo_gstate.c b/src/cairo_gstate.c
index ff3a2c659..7599d44cc 100644
--- a/src/cairo_gstate.c
+++ b/src/cairo_gstate.c
@@ -1435,12 +1435,15 @@ _cairo_gstate_clip_and_composite_trapezoids (cairo_gstate_t *gstate,
if (status)
goto BAIL2;
+ if (dst == gstate->clip.surface)
+ xoff = yoff = 0;
+
status = _cairo_surface_composite (operator,
pattern.source, intermediate, dst,
0, 0,
0, 0,
- gstate->clip.x,
- gstate->clip.y,
+ xoff >> 16,
+ yoff >> 16,
gstate->clip.width,
gstate->clip.height);
@@ -1643,9 +1646,6 @@ extract_transformed_rectangle(cairo_matrix_t *mat,
cairo_traps_t *tr,
pixman_box16_t *box)
{
-#define CAIRO_FIXED_IS_INTEGER(x) (((x) & 0xFFFF) == 0)
-#define CAIRO_FIXED_INTEGER_PART(x) ((x) >> 16)
-
double a, b, c, d, tx, ty;
cairo_status_t st;
@@ -1658,25 +1658,22 @@ extract_transformed_rectangle(cairo_matrix_t *mat,
&& tr->traps[0].right.p1.x == tr->traps[0].right.p2.x
&& tr->traps[0].left.p1.y == tr->traps[0].right.p1.y
&& tr->traps[0].left.p2.y == tr->traps[0].right.p2.y
- && CAIRO_FIXED_IS_INTEGER(tr->traps[0].left.p1.x)
- && CAIRO_FIXED_IS_INTEGER(tr->traps[0].left.p1.y)
- && CAIRO_FIXED_IS_INTEGER(tr->traps[0].left.p2.x)
- && CAIRO_FIXED_IS_INTEGER(tr->traps[0].left.p2.y)
- && CAIRO_FIXED_IS_INTEGER(tr->traps[0].right.p1.x)
- && CAIRO_FIXED_IS_INTEGER(tr->traps[0].right.p1.y)
- && CAIRO_FIXED_IS_INTEGER(tr->traps[0].right.p2.x)
- && CAIRO_FIXED_IS_INTEGER(tr->traps[0].right.p2.y)) {
-
- box->x1 = (short) CAIRO_FIXED_INTEGER_PART(tr->traps[0].left.p1.x);
- box->x2 = (short) CAIRO_FIXED_INTEGER_PART(tr->traps[0].right.p1.x);
- box->y1 = (short) CAIRO_FIXED_INTEGER_PART(tr->traps[0].left.p1.y);
- box->y2 = (short) CAIRO_FIXED_INTEGER_PART(tr->traps[0].left.p2.y);
+ && _cairo_fixed_is_integer(tr->traps[0].left.p1.x)
+ && _cairo_fixed_is_integer(tr->traps[0].left.p1.y)
+ && _cairo_fixed_is_integer(tr->traps[0].left.p2.x)
+ && _cairo_fixed_is_integer(tr->traps[0].left.p2.y)
+ && _cairo_fixed_is_integer(tr->traps[0].right.p1.x)
+ && _cairo_fixed_is_integer(tr->traps[0].right.p1.y)
+ && _cairo_fixed_is_integer(tr->traps[0].right.p2.x)
+ && _cairo_fixed_is_integer(tr->traps[0].right.p2.y)) {
+
+ box->x1 = (short) _cairo_fixed_integer_part(tr->traps[0].left.p1.x);
+ box->x2 = (short) _cairo_fixed_integer_part(tr->traps[0].right.p1.x);
+ box->y1 = (short) _cairo_fixed_integer_part(tr->traps[0].left.p1.y);
+ box->y2 = (short) _cairo_fixed_integer_part(tr->traps[0].left.p2.y);
return 1;
}
return 0;
-
-#undef CAIRO_FIXED_IS_INTEGER
-#undef CAIRO_FIXED_INTEGER_PART
}
cairo_status_t
@@ -1743,20 +1740,20 @@ _cairo_gstate_clip (cairo_gstate_t *gstate)
_cairo_color_init (&white_color);
if (gstate->clip.surface == NULL) {
- double x1, y1, x2, y2;
- _cairo_path_bounds (&gstate->path,
- &x1, &y1, &x2, &y2);
- gstate->clip.x = floor (x1);
- gstate->clip.y = floor (y1);
- gstate->clip.width = ceil (x2 - gstate->clip.x);
- gstate->clip.height = ceil (y2 - gstate->clip.y);
- gstate->clip.surface =
- _cairo_surface_create_similar_solid (gstate->surface,
- CAIRO_FORMAT_A8,
- gstate->clip.width,
- gstate->clip.height,
- &white_color);
- if (gstate->clip.surface == NULL)
+ cairo_box_t extents;
+
+ _cairo_traps_extents (&traps, &extents);
+ gstate->clip.x = extents.p1.x >> 16;
+ gstate->clip.y = extents.p1.y >> 16;
+ gstate->clip.width = ((extents.p2.x + 65535) >> 16) - gstate->clip.x;
+ gstate->clip.height = ((extents.p2.y + 65535) >> 16) - gstate->clip.y;
+ gstate->clip.surface =
+ _cairo_surface_create_similar_solid (gstate->surface,
+ CAIRO_FORMAT_A8,
+ gstate->clip.width,
+ gstate->clip.height,
+ &white_color);
+ if (gstate->clip.surface == NULL)
return CAIRO_STATUS_NO_MEMORY;
}
@@ -1782,14 +1779,78 @@ _cairo_gstate_show_surface (cairo_gstate_t *gstate,
int width,
int height)
{
+
+ /* We are dealing with 5 coordinate spaces in this function. this makes
+ * it ugly.
+ *
+ * - "Image" space is the space of the surface we're reading pixels from.
+ * it is the surface argument to this function. The surface has a
+ * matrix attached to it which maps "user" space (see below) into
+ * image space.
+ *
+ * - "Device" space is the space of the surface we're ultimately writing
+ * pixels to. It is the current surface of the gstate argument to
+ * this function.
+ *
+ * - "User" space is an arbitrary space defined by the user, defined
+ * implicitly by the gstate's CTM. The CTM maps from user space to
+ * device space. The CTM inverse (which is also kept at all times)
+ * maps from device space to user space.
+ *
+ * - "Clip" space is the space of the surface being used to clip pixels
+ * during compositing. Space-wise, it is a bounding box (offset+size)
+ * within device space. This surface is usually smaller than the device
+ * surface (and possibly the image surface too) and logically occupies
+ * a bounding box around the "clip path", situated somewhere in device
+ * space. The clip path is already painted on the clip surface.
+ *
+ * - "Pattern" space is another arbitrary space defined in the pattern
+ * element of gstate. As pixels are read from image space, they are
+ * combined with pixels being read from pattern space and pixels
+ * already existing in device space. User coordinates are converted
+ * to pattern space, similarly, using a matrix attached to the pattern.
+ * (in fact, there is a 6th space in here, which is the space of the
+ * surface acting as a source for the pattern)
+ *
+ * To composite these spaces, we temporarily change the image surface
+ * so that it can be read and written in device coordinates; in a sense
+ * this makes it "spatially compatible" with the clip and device spaces.
+ *
+ *
+ * There is also some confusion about the interaction between a clip and
+ * a pattern; it is assumed that in this "show surface" operation a pattern
+ * is to be used as an auxiliary alpha mask. this might be wrong, but it's
+ * what we're doing now.
+ *
+ * so, to follow the operations below, remember that in the compositing
+ * model, each operation is always of the form ((src IN mask) OP dst).
+ * that's the basic operation.
+ *
+ * so the compositing we are trying to do here, in general, involves 2
+ * steps, going via a temporary surface:
+ *
+ * - combining clip and pattern pixels together into a mask channel.
+ * this will be ((pattern IN clip) SRC temporary). it ignores the
+ * pixels already in the temporary, overwriting it with the
+ * pattern, clipped to the clip mask.
+ *
+ * - combining temporary and "image" pixels with "device" pixels,
+ * with a user-provided porter/duff operator. this will be
+ * ((image IN temporary) OP device).
+ *
+ * if there is no clip, the degenerate case is just the second step
+ * with pattern standing in for temporary.
+ *
+ */
+
cairo_status_t status;
cairo_matrix_t user_to_image, image_to_user;
cairo_matrix_t image_to_device, device_to_image;
double device_x, device_y;
double device_width, device_height;
cairo_pattern_t pattern;
- cairo_box_t extents;
-
+ cairo_box_t pattern_extents;
+
cairo_surface_get_matrix (surface, &user_to_image);
cairo_matrix_multiply (&device_to_image, &gstate->ctm_inverse, &user_to_image);
cairo_surface_set_matrix (surface, &device_to_image);
@@ -1808,31 +1869,84 @@ _cairo_gstate_show_surface (cairo_gstate_t *gstate,
_cairo_pattern_init (&pattern);
if ((gstate->pattern->type != CAIRO_PATTERN_SOLID) ||
- (gstate->alpha != 1.0)) {
+ (gstate->alpha != 1.0)) {
/* I'm allowing any type of pattern for the mask right now.
Maybe this is bad. Will allow for some cool effects though. */
_cairo_pattern_init_copy (&pattern, gstate->pattern);
- extents.p1.x = _cairo_fixed_from_double (device_x);
- extents.p1.y = _cairo_fixed_from_double (device_y);
- extents.p2.x = _cairo_fixed_from_double (device_x + device_width);
- extents.p2.y = _cairo_fixed_from_double (device_y + device_height);
- status = _cairo_gstate_create_pattern (gstate, &pattern, &extents);
+ pattern_extents.p1.x = _cairo_fixed_from_double (device_x);
+ pattern_extents.p1.y = _cairo_fixed_from_double (device_y);
+ pattern_extents.p2.x = _cairo_fixed_from_double (device_x + device_width);
+ pattern_extents.p2.y = _cairo_fixed_from_double (device_y + device_height);
+ status = _cairo_gstate_create_pattern (gstate, &pattern, &pattern_extents);
if (status)
return status;
}
- /* XXX: The rendered size is sometimes 1 or 2 pixels short from
- what I expect. Need to fix this. */
- status = _cairo_surface_composite (gstate->operator,
- surface, pattern.source, gstate->surface,
- device_x, device_y,
- 0, 0,
- device_x, device_y,
- device_width,
- device_height);
+ if (gstate->clip.surface)
+ {
+ cairo_surface_t *intermediate;
+ cairo_color_t empty_color;
- _cairo_pattern_fini (&pattern);
+ _cairo_color_init (&empty_color);
+ _cairo_color_set_alpha (&empty_color, .0);
+ intermediate = _cairo_surface_create_similar_solid (gstate->clip.surface,
+ CAIRO_FORMAT_A8,
+ gstate->clip.width,
+ gstate->clip.height,
+ &empty_color);
+
+ /* it is not completely clear what the "right" way to combine the
+ pattern and mask surface is. I will use the the clip as a source
+ and the pattern as a mask in building up my temporary, because
+ this is not *totally* bogus and accomodates the case where
+ pattern's source image is NULL reasonably well. feel free to
+ correct this if you see a reason. */
+
+ status = _cairo_surface_composite (CAIRO_OPERATOR_SRC,
+ gstate->clip.surface,
+ pattern.source,
+ intermediate,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ gstate->clip.width,
+ gstate->clip.height);
+
+ if (status)
+ goto BAIL;
+
+ status = _cairo_surface_composite (gstate->operator,
+ surface,
+ intermediate,
+ gstate->surface,
+ gstate->clip.x, gstate->clip.y,
+ 0, 0,
+ gstate->clip.x, gstate->clip.y,
+ gstate->clip.width,
+ gstate->clip.height);
+
+ BAIL:
+ cairo_surface_destroy (intermediate);
+ }
+ else
+ {
+
+ /* XXX: The rendered size is sometimes 1 or 2 pixels short from
+ what I expect. Need to fix this. */
+ status = _cairo_surface_composite (gstate->operator,
+ surface,
+ pattern.source,
+ gstate->surface,
+ device_x, device_y,
+ 0, 0,
+ device_x, device_y,
+ device_width,
+ device_height);
+
+ }
+ _cairo_pattern_fini (&pattern);
+
/* restore the matrix originally in the surface */
cairo_surface_set_matrix (surface, &user_to_image);
@@ -2004,10 +2118,62 @@ _cairo_gstate_show_text (cairo_gstate_t *gstate,
status = _cairo_gstate_create_pattern (gstate, &pattern, &extents);
if (status)
return status;
-
- status = _cairo_font_show_text (gstate->font,
- gstate->operator, pattern.source,
- gstate->surface, x, y, utf8);
+ if (gstate->clip.surface)
+ {
+ cairo_surface_t *intermediate;
+ cairo_color_t empty_color;
+
+ _cairo_color_init (&empty_color);
+ _cairo_color_set_alpha (&empty_color, .0);
+ intermediate = _cairo_surface_create_similar_solid (gstate->clip.surface,
+ CAIRO_FORMAT_A8,
+ gstate->clip.width,
+ gstate->clip.height,
+ &empty_color);
+
+ status = _cairo_font_show_text (gstate->font,
+ CAIRO_OPERATOR_ADD, pattern.source,
+ intermediate,
+ x - gstate->clip.x,
+ y - gstate->clip.y, utf8);
+
+ if (status)
+ goto BAIL;
+
+ status = _cairo_surface_composite (CAIRO_OPERATOR_IN,
+ gstate->clip.surface,
+ NULL,
+ intermediate,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ gstate->clip.width,
+ gstate->clip.height);
+
+ if (status)
+ goto BAIL;
+
+ status = _cairo_surface_composite (gstate->operator,
+ pattern.source,
+ intermediate,
+ gstate->surface,
+ 0, 0,
+ 0, 0,
+ gstate->clip.x,
+ gstate->clip.y,
+ gstate->clip.width,
+ gstate->clip.height);
+
+ BAIL:
+ cairo_surface_destroy (intermediate);
+
+ }
+ else
+ {
+ status = _cairo_font_show_text (gstate->font,
+ gstate->operator, pattern.source,
+ gstate->surface, x, y, utf8);
+ }
cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix);
@@ -2045,8 +2211,8 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
cairo_matrix_multiply (&gstate->font->matrix, &gstate->ctm, &gstate->font->matrix);
_cairo_pattern_init_copy (&pattern, gstate->pattern);
- _cairo_gstate_glyph_extents (gstate, transformed_glyphs, num_glyphs,
- &text_extents);
+ status = _cairo_gstate_glyph_extents (gstate, transformed_glyphs, num_glyphs,
+ &text_extents);
if (status)
return status;
@@ -2059,11 +2225,70 @@ _cairo_gstate_show_glyphs (cairo_gstate_t *gstate,
status = _cairo_gstate_create_pattern (gstate, &pattern, &extents);
if (status)
return status;
+
+ if (gstate->clip.surface)
+ {
+ cairo_surface_t *intermediate;
+ cairo_color_t empty_color;
+
+ _cairo_color_init (&empty_color);
+ _cairo_color_set_alpha (&empty_color, .0);
+ intermediate = _cairo_surface_create_similar_solid (gstate->clip.surface,
+ CAIRO_FORMAT_A8,
+ gstate->clip.width,
+ gstate->clip.height,
+ &empty_color);
+
+ /* move the glyphs again, from dev space to clip space */
+ for (i = 0; i < num_glyphs; ++i)
+ {
+ transformed_glyphs[i].x -= gstate->clip.x;
+ transformed_glyphs[i].y -= gstate->clip.y;
+ }
+
+ status = _cairo_font_show_glyphs (gstate->font,
+ CAIRO_OPERATOR_ADD,
+ pattern.source, intermediate,
+ transformed_glyphs, num_glyphs);
+
+ if (status)
+ goto BAIL;
- status = _cairo_font_show_glyphs (gstate->font,
- gstate->operator, pattern.source,
- gstate->surface,
- transformed_glyphs, num_glyphs);
+ status = _cairo_surface_composite (CAIRO_OPERATOR_IN,
+ gstate->clip.surface,
+ NULL,
+ intermediate,
+ 0, 0,
+ 0, 0,
+ 0, 0,
+ gstate->clip.width,
+ gstate->clip.height);
+
+ if (status)
+ goto BAIL;
+
+ status = _cairo_surface_composite (gstate->operator,
+ pattern.source,
+ intermediate,
+ gstate->surface,
+ 0, 0,
+ 0, 0,
+ gstate->clip.x,
+ gstate->clip.y,
+ gstate->clip.width,
+ gstate->clip.height);
+
+ BAIL:
+ cairo_surface_destroy (intermediate);
+
+ }
+ else
+ {
+ status = _cairo_font_show_glyphs (gstate->font,
+ gstate->operator, pattern.source,
+ gstate->surface,
+ transformed_glyphs, num_glyphs);
+ }
cairo_matrix_copy (&gstate->font->matrix, &saved_font_matrix);
diff --git a/src/cairo_matrix.c b/src/cairo_matrix.c
index de89c0fd5..cc5635fff 100644
--- a/src/cairo_matrix.c
+++ b/src/cairo_matrix.c
@@ -405,3 +405,27 @@ _cairo_matrix_compute_scale_factors (cairo_matrix_t *matrix, double *sx, double
return CAIRO_STATUS_SUCCESS;
}
+
+int
+_cairo_matrix_is_integer_translation(cairo_matrix_t *mat,
+ int *itx, int *ity)
+{
+ double a, b, c, d, tx, ty;
+ int ttx, tty;
+ int ok = 0;
+ cairo_matrix_get_affine (mat, &a, &b, &c, &d, &tx, &ty);
+ ttx = _cairo_fixed_from_double (tx);
+ tty = _cairo_fixed_from_double (ty);
+ ok = ((a == 1.0)
+ && (b == 0.0)
+ && (c == 0.0)
+ && (d == 1.0)
+ && (_cairo_fixed_is_integer(ttx))
+ && (_cairo_fixed_is_integer(tty)));
+ if (ok) {
+ *itx = _cairo_fixed_integer_part(ttx);
+ *ity = _cairo_fixed_integer_part(tty);
+ return 1;
+ }
+ return 0;
+}
diff --git a/src/cairo_xlib_surface.c b/src/cairo_xlib_surface.c
index 19dfde503..b54284aa2 100644
--- a/src/cairo_xlib_surface.c
+++ b/src/cairo_xlib_surface.c
@@ -455,7 +455,8 @@ _cairo_xlib_surface_composite (cairo_operator_t operator,
cairo_xlib_surface_t *mask = (cairo_xlib_surface_t *) generic_mask;
cairo_xlib_surface_t *src_clone = NULL;
cairo_xlib_surface_t *mask_clone = NULL;
-
+ XGCValues gc_values;
+ int src_x_off, src_y_off, dst_x_off, dst_y_off;
if (!CAIRO_SURFACE_RENDER_HAS_COMPOSITE (dst))
return CAIRO_INT_STATUS_UNSUPPORTED;
@@ -475,6 +476,28 @@ _cairo_xlib_surface_composite (cairo_operator_t operator,
mask = mask_clone;
}
+ if (operator == CAIRO_OPERATOR_SRC
+ && !mask
+ && _cairo_matrix_is_integer_translation(&(src->base.matrix),
+ &src_x_off, &src_y_off)
+ && _cairo_matrix_is_integer_translation(&(dst->base.matrix),
+ &dst_x_off, &dst_y_off)) {
+ /* Fast path for copying "raw" areas. */
+ _cairo_xlib_surface_ensure_gc (dst);
+ XGetGCValues(dst->dpy, dst->gc, GCGraphicsExposures, &gc_values);
+ XSetGraphicsExposures(dst->dpy, dst->gc, False);
+ XCopyArea(dst->dpy,
+ src->drawable,
+ dst->drawable,
+ dst->gc,
+ src_x + src_x_off,
+ src_y + src_y_off,
+ width, height,
+ dst_x + dst_x_off,
+ dst_y + dst_y_off);
+ XSetGraphicsExposures(dst->dpy, dst->gc, gc_values.graphics_exposures);
+
+ } else {
XRenderComposite (dst->dpy,
_render_operator (operator),
src->picture,
@@ -484,6 +507,7 @@ _cairo_xlib_surface_composite (cairo_operator_t operator,
mask_x, mask_y,
dst_x, dst_y,
width, height);
+ }
/* XXX: This is messed up. If I can xlib_surface_create, then I
should be able to xlib_surface_destroy. */
@@ -577,8 +601,11 @@ static cairo_int_status_t
_cairo_xlib_surface_set_clip_region (void *abstract_surface,
pixman_region16_t *region)
{
+
Region xregion;
XRectangle xr;
+ XRectangle *rects = NULL;
+ XGCValues gc_values;
pixman_box16_t *box;
cairo_xlib_surface_t *surf;
int n, m;
@@ -593,13 +620,17 @@ _cairo_xlib_surface_set_clip_region (void *abstract_surface,
xr.width = surf->width;
xr.height = surf->height;
XUnionRectWithRegion (&xr, xregion, xregion);
+ rects = malloc(sizeof(XRectangle));
+ rects[0] = xr;
+ m = 1;
+
} else {
n = pixman_region_num_rects (region);
/* XXX: Are we sure these are the semantics we want for an
* empty, (not null) region? */
if (n == 0)
return CAIRO_STATUS_SUCCESS;
-
+ rects = malloc(sizeof(XRectangle) * n);
box = pixman_region_rects (region);
xregion = XCreateRegion();
@@ -609,13 +640,20 @@ _cairo_xlib_surface_set_clip_region (void *abstract_surface,
xr.y = (short) box->y1;
xr.width = (unsigned short) (box->x2 - box->x1);
xr.height = (unsigned short) (box->y2 - box->y1);
+ rects[n-1] = xr;
XUnionRectWithRegion (&xr, xregion, xregion);
}
}
+ _cairo_xlib_surface_ensure_gc (surf);
+ XGetGCValues(surf->dpy, surf->gc, GCGraphicsExposures, &gc_values);
+ XSetGraphicsExposures(surf->dpy, surf->gc, False);
+ XSetClipRectangles(surf->dpy, surf->gc, 0, 0, rects, m, Unsorted);
+ free(rects);
+ if (surf->picture)
XRenderSetPictureClipRegion (surf->dpy, surf->picture, xregion);
XDestroyRegion(xregion);
-
+ XSetGraphicsExposures(surf->dpy, surf->gc, gc_values.graphics_exposures);
return CAIRO_STATUS_SUCCESS;
}
@@ -654,6 +692,8 @@ cairo_xlib_surface_create (Display *dpy,
{
cairo_xlib_surface_t *surface;
int render_standard;
+ Window w;
+ unsigned int ignore;
surface = malloc (sizeof (cairo_xlib_surface_t));
if (surface == NULL)
@@ -692,6 +732,12 @@ cairo_xlib_surface_create (Display *dpy,
break;
}
+ XGetGeometry(dpy, drawable,
+ &w, &ignore, &ignore,
+ &surface->width,
+ &surface->height,
+ &ignore, &ignore);
+
/* XXX: I'm currently ignoring the colormap. Is that bad? */
if (CAIRO_SURFACE_RENDER_HAS_CREATE_PICTURE (surface))
surface->picture = XRenderCreatePicture (dpy, drawable,
diff --git a/src/cairoint.h b/src/cairoint.h
index 5a016fd20..8ace018e3 100644
--- a/src/cairoint.h
+++ b/src/cairoint.h
@@ -620,6 +620,12 @@ _cairo_fixed_from_26_6 (uint32_t i);
extern double
_cairo_fixed_to_double (cairo_fixed_t f);
+extern int __internal_linkage
+_cairo_fixed_is_integer (cairo_fixed_t f);
+
+extern int __internal_linkage
+_cairo_fixed_integer_part (cairo_fixed_t f);
+
/* cairo_gstate.c */
extern cairo_gstate_t * __internal_linkage
_cairo_gstate_create (void);
@@ -1287,6 +1293,9 @@ _cairo_matrix_compute_eigen_values (cairo_matrix_t *matrix, double *lambda1, dou
extern cairo_status_t __internal_linkage
_cairo_matrix_compute_scale_factors (cairo_matrix_t *matrix, double *sx, double *sy);
+extern int __internal_linkage
+_cairo_matrix_is_integer_translation(cairo_matrix_t *matrix, int *itx, int *ity);
+
/* cairo_traps.c */
extern void __internal_linkage
_cairo_traps_init (cairo_traps_t *traps);