diff options
author | Graydon Hoare <graydon@redhat.com> | 2004-05-20 16:42:56 +0000 |
---|---|---|
committer | Graydon Hoare <graydon@redhat.com> | 2004-05-20 16:42:56 +0000 |
commit | 23026d5ab65201793ac19b459e3e7e05a090e435 (patch) | |
tree | 4e3b57692a89e26b22a29507ad68c2496ea922b9 | |
parent | aab2fe8c059cc41451ddf5e0719f18d77ef354f4 (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-- | ChangeLog | 29 | ||||
-rw-r--r-- | configure.in | 14 | ||||
-rw-r--r-- | src/cairo-features.h.in | 2 | ||||
-rw-r--r-- | src/cairo-fixed.c | 11 | ||||
-rw-r--r-- | src/cairo-gstate.c | 351 | ||||
-rw-r--r-- | src/cairo-matrix.c | 24 | ||||
-rw-r--r-- | src/cairo-xlib-surface.c | 52 | ||||
-rw-r--r-- | src/cairo.c | 187 | ||||
-rw-r--r-- | src/cairo_fixed.c | 11 | ||||
-rw-r--r-- | src/cairo_gstate.c | 351 | ||||
-rw-r--r-- | src/cairo_matrix.c | 24 | ||||
-rw-r--r-- | src/cairo_xlib_surface.c | 52 | ||||
-rw-r--r-- | src/cairoint.h | 9 |
13 files changed, 982 insertions, 135 deletions
@@ -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); |