Index: src/cairo-gstate.c =================================================================== --- src/cairo-gstate.c.orig 2006-02-10 11:20:53.187500000 -0800 +++ src/cairo-gstate.c 2006-02-10 14:05:49.891625000 -0800 @@ -508,37 +508,10 @@ return gstate->stroke_style.miter_limit; } -static void -_cairo_gstate_apply_device_transform (cairo_gstate_t *gstate, - cairo_matrix_t *matrix) -{ - if (gstate->target->device_x_scale != 1.0 || - gstate->target->device_y_scale != 1.0) - { - cairo_matrix_scale (matrix, - gstate->target->device_x_scale, - gstate->target->device_y_scale); - } -} - -static void -_cairo_gstate_apply_device_inverse_transform (cairo_gstate_t *gstate, - cairo_matrix_t *matrix) -{ - if (gstate->target->device_x_scale != 1.0 || - gstate->target->device_y_scale != 1.0) - { - cairo_matrix_scale (matrix, - 1/gstate->target->device_x_scale, - 1/gstate->target->device_y_scale); - } -} - void _cairo_gstate_get_matrix (cairo_gstate_t *gstate, cairo_matrix_t *matrix) { *matrix = gstate->ctm; - _cairo_gstate_apply_device_inverse_transform (gstate, matrix); } cairo_status_t @@ -624,9 +597,6 @@ if (status) return status; - _cairo_gstate_apply_device_transform (gstate, &gstate->ctm); - _cairo_gstate_apply_device_inverse_transform (gstate, &gstate->ctm_inverse); - return CAIRO_STATUS_SUCCESS; } @@ -638,9 +608,6 @@ cairo_matrix_init_identity (&gstate->ctm); cairo_matrix_init_identity (&gstate->ctm_inverse); - _cairo_gstate_apply_device_transform (gstate, &gstate->ctm); - _cairo_gstate_apply_device_inverse_transform (gstate, &gstate->ctm_inverse); - return CAIRO_STATUS_SUCCESS; } @@ -682,15 +649,11 @@ _cairo_gstate_user_to_backend (cairo_gstate_t *gstate, double *x, double *y) { cairo_matrix_transform_point (&gstate->ctm, x, y); - *x += gstate->target->device_x_offset; - *y += gstate->target->device_y_offset; } void _cairo_gstate_backend_to_user (cairo_gstate_t *gstate, double *x, double *y) { - *x -= gstate->target->device_x_offset; - *y -= gstate->target->device_y_offset; cairo_matrix_transform_point (&gstate->ctm_inverse, x, y); } @@ -711,16 +674,8 @@ cairo_pattern_t *original, cairo_matrix_t *ctm_inverse) { - cairo_matrix_t tmp_matrix = *ctm_inverse; - _cairo_pattern_init_copy (pattern, original); - - if (gstate->target) - cairo_matrix_translate (&tmp_matrix, - - gstate->target->device_x_offset, - - gstate->target->device_y_offset); - - _cairo_pattern_transform (pattern, &tmp_matrix); + _cairo_pattern_transform (pattern, ctm_inverse); } static void @@ -1401,9 +1356,6 @@ if (status || !glyphs || !num_glyphs || !(*glyphs) || !(num_glyphs)) return status; - _cairo_gstate_apply_device_transform (gstate, &gstate->ctm); - _cairo_gstate_apply_device_inverse_transform (gstate, &gstate->ctm_inverse); - return CAIRO_STATUS_SUCCESS; } @@ -1440,9 +1392,6 @@ glyphs, num_glyphs, extents); - _cairo_gstate_apply_device_transform (gstate, &gstate->ctm); - _cairo_gstate_apply_device_inverse_transform (gstate, &gstate->ctm_inverse); - return CAIRO_STATUS_SUCCESS; } Index: src/cairo-path.c =================================================================== --- src/cairo-path.c.orig 2006-02-10 11:20:53.188500000 -0800 +++ src/cairo-path.c 2006-02-10 11:30:54.359375000 -0800 @@ -548,3 +548,40 @@ return CAIRO_STATUS_SUCCESS; } + +void +_cairo_path_fixed_offset_and_scale (cairo_path_fixed_t *path, + cairo_fixed_t offx, + cairo_fixed_t offy, + cairo_fixed_t scalex, + cairo_fixed_t scaley) +{ + cairo_path_arg_buf_t *arg_buf = path->arg_buf_head; + int i; + cairo_int64_t i64temp; + cairo_fixed_t fixedtemp; + + while (arg_buf) { + for (i = 0; i < arg_buf->num_points; i++) { + /* CAIRO_FIXED_ONE? */ + if (scalex == 0x00010000) { + arg_buf->points[i].x += offx; + } else { + fixedtemp = arg_buf->points[i].x + offx; + i64temp = _cairo_int32x32_64_mul (fixedtemp, scalex); + arg_buf->points[i].x = _cairo_int64_to_int32(_cairo_int64_rsl (i64temp, 16)); + } + + if (scaley == 0x00010000) { + arg_buf->points[i].y += offy; + } else { + fixedtemp = arg_buf->points[i].y + offy; + i64temp = _cairo_int32x32_64_mul (fixedtemp, scaley); + arg_buf->points[i].y = _cairo_int64_to_int32(_cairo_int64_rsl (i64temp, 16)); + } + } + + arg_buf = arg_buf->next; + } +} + Index: src/cairo-surface-fallback.c =================================================================== --- src/cairo-surface-fallback.c.orig 2006-02-10 11:20:53.190500000 -0800 +++ src/cairo-surface-fallback.c 2006-02-10 11:30:54.375000000 -0800 @@ -214,6 +214,21 @@ */ _cairo_pattern_init_for_surface (&dst_pattern, dst); + /* Set a translation on dst_pattern equivalent to the surface + * device offset, to make sure it's in the right place when + * composited. + */ + if (dst->device_x_offset != 0.0 || + dst->device_y_offset != 0.0 || + dst->device_x_scale != 1.0 || + dst->device_y_scale != 1.0) + { + cairo_matrix_t txmat; + cairo_matrix_init_scale (&txmat, dst->device_x_scale, dst->device_y_scale); + cairo_matrix_translate (&txmat, dst->device_x_offset, dst->device_y_offset); + cairo_pattern_set_matrix ((cairo_pattern_t*) &dst_pattern, &txmat); + } + status = _cairo_surface_composite (CAIRO_OPERATOR_SOURCE, &dst_pattern.base, NULL, intermediate, extents->x, extents->y, @@ -888,7 +903,8 @@ op, src, dst, extents->x, extents->y, - extents->x - dst_x, extents->y - dst_y, + extents->x - dst_x + dst->device_x_offset, + extents->y - dst_y + dst->device_y_offset, extents->width, extents->height, glyph_info->glyphs, glyph_info->num_glyphs); @@ -982,6 +998,11 @@ _cairo_surface_release_source_image (surface, image, &image_extra); + snapshot->device_x_offset = surface->device_x_offset; + snapshot->device_y_offset = surface->device_y_offset; + snapshot->device_x_scale = surface->device_x_scale; + snapshot->device_y_scale = surface->device_y_scale; + snapshot->is_snapshot = TRUE; return snapshot; @@ -1011,12 +1032,17 @@ return status; } - status = state.image->base.backend->composite (op, src, mask, - &state.image->base, - src_x, src_y, mask_x, mask_y, - dst_x - state.image_rect.x, - dst_y - state.image_rect.y, - width, height); + /* We know this will never fail with the image backend; but + * instead of calling into it directly, we call + * _cairo_surface_composite so that we get the correct device + * offset handling. + */ + status = _cairo_surface_composite (op, src, mask, + &state.image->base, + src_x, src_y, mask_x, mask_y, + dst_x - state.image_rect.x, + dst_y - state.image_rect.y, + width, height); _fallback_fini (&state); return status; @@ -1086,9 +1112,9 @@ rects = offset_rects; } - status = state.image->base.backend->fill_rectangles (&state.image->base, - op, color, - rects, num_rects); + status = _cairo_surface_fill_rectangles (&state.image->base, + op, color, + rects, num_rects); free (offset_rects); @@ -1127,39 +1153,25 @@ /* If the destination image isn't at 0,0, we need to offset the trapezoids */ if (state.image_rect.x != 0 || state.image_rect.y != 0) { - - cairo_fixed_t xoff = _cairo_fixed_from_int (state.image_rect.x); - cairo_fixed_t yoff = _cairo_fixed_from_int (state.image_rect.y); - offset_traps = malloc (sizeof (cairo_trapezoid_t) * num_traps); if (!offset_traps) { status = CAIRO_STATUS_NO_MEMORY; goto DONE; } - for (i = 0; i < num_traps; i++) { - offset_traps[i].top = traps[i].top - yoff; - offset_traps[i].bottom = traps[i].bottom - yoff; - offset_traps[i].left.p1.x = traps[i].left.p1.x - xoff; - offset_traps[i].left.p1.y = traps[i].left.p1.y - yoff; - offset_traps[i].left.p2.x = traps[i].left.p2.x - xoff; - offset_traps[i].left.p2.y = traps[i].left.p2.y - yoff; - offset_traps[i].right.p1.x = traps[i].right.p1.x - xoff; - offset_traps[i].right.p1.y = traps[i].right.p1.y - yoff; - offset_traps[i].right.p2.x = traps[i].right.p2.x - xoff; - offset_traps[i].right.p2.y = traps[i].right.p2.y - yoff; - } - + _cairo_trapezoid_array_translate_and_scale (offset_traps, traps, num_traps, + - state.image_rect.x, - state.image_rect.y, + 1.0, 1.0); traps = offset_traps; } - state.image->base.backend->composite_trapezoids (op, pattern, - &state.image->base, - antialias, - src_x, src_y, - dst_x - state.image_rect.x, - dst_y - state.image_rect.y, - width, height, traps, num_traps); + _cairo_surface_composite_trapezoids (op, pattern, + &state.image->base, + antialias, + src_x, src_y, + dst_x - state.image_rect.x, + dst_y - state.image_rect.y, + width, height, traps, num_traps); if (offset_traps) free (offset_traps); Index: src/cairo-surface.c =================================================================== --- src/cairo-surface.c.orig 2006-02-10 11:20:53.191500000 -0800 +++ src/cairo-surface.c 2006-02-10 11:30:54.375000000 -0800 @@ -89,6 +89,22 @@ 0 /* current_clip_serial */ }; +/* N.B.: set_device_offset already transforms the device offsets by the scale + * before storing in device_[xy]_scale + */ + +/* Helper macros for transforming surface coords to backend coords */ +#define BACKEND_X(_surf, _sx) ((_sx)*((_surf)->device_x_scale)+((_surf)->device_x_offset)) +#define BACKEND_Y(_surf, _sy) ((_sy)*((_surf)->device_y_scale)+((_surf)->device_y_offset)) +#define BACKEND_X_SIZE(_surf, _sx) ((_sx)*((_surf)->device_x_scale)) +#define BACKEND_Y_SIZE(_surf, _sy) ((_sy)*((_surf)->device_y_scale)) + +/* Helper macros for transforming backend coords to surface coords */ +#define SURFACE_X(_surf, _bx) (((_bx)-((_surf)->device_x_offset))/((_surf)->device_x_scale)) +#define SURFACE_Y(_surf, _by) (((_by)-((_surf)->device_y_offset))/((_surf)->device_y_scale)) +#define SURFACE_X_SIZE(_surf, _bx) ((_bx)/((_surf)->device_x_scale)) +#define SURFACE_Y_SIZE(_surf, _by) ((_by)/((_surf)->device_y_scale)) + /** * _cairo_surface_set_error: * @surface: a surface @@ -533,7 +549,10 @@ if (surface->backend->mark_dirty_rectangle) { cairo_status_t status; - status = surface->backend->mark_dirty_rectangle (surface, x, y, width, height); + status = surface->backend->mark_dirty_rectangle (surface, + BACKEND_X(surface, x), + BACKEND_Y(surface, y), + width, height); if (status) _cairo_surface_set_error (surface, status); @@ -578,6 +597,25 @@ } /** + * cairo_surface_get_device_offset: + * @surface: a #cairo_surface_t + * @x_offset: the offset in the X direction, in device units + * @y_offset: the offset in the Y direction, in device units + * + * Returns a previous device offset set by + * cairo_surface_set_device_offset(). + * + **/ +void +cairo_surface_get_device_offset (cairo_surface_t *surface, + double *x_offset, + double *y_offset) +{ + *x_offset = surface->device_x_offset; + *y_offset = surface->device_y_offset; +} + +/** * _cairo_surface_acquire_source_image: * @surface: a #cairo_surface_t * @image_out: location to store a pointer to an image surface that @@ -628,6 +666,7 @@ * @surface: a #cairo_surface_t * @interest_rect: area of @surface for which fallback drawing is being done. * A value of %NULL indicates that the entire surface is desired. + * XXXX I'd like to get rid of being able to pass NULL here (nothing seems to) * @image_out: location to store a pointer to an image surface that includes at least * the intersection of @interest_rect with the visible area of @surface. * This surface could be @surface itself, a surface held internal to @surface, @@ -660,10 +699,26 @@ cairo_rectangle_t *image_rect, void **image_extra) { + cairo_rectangle_t dev_interest_rect; + cairo_status_t status; + assert (!surface->finished); - return surface->backend->acquire_dest_image (surface, interest_rect, - image_out, image_rect, image_extra); + if (interest_rect) { + dev_interest_rect = *interest_rect; + dev_interest_rect.x = BACKEND_X(surface, dev_interest_rect.x); + dev_interest_rect.y = BACKEND_Y(surface, dev_interest_rect.y); + } + + status = surface->backend->acquire_dest_image (surface, + interest_rect ? &dev_interest_rect : NULL, + image_out, image_rect, image_extra); + + /* move image_rect back into surface coordinates from backend device coordinates */ + image_rect->x = SURFACE_X(surface, image_rect->x); + image_rect->y = SURFACE_Y(surface, image_rect->y); + + return status; } /** @@ -685,10 +740,22 @@ cairo_rectangle_t *image_rect, void *image_extra) { + cairo_rectangle_t dev_interest_rect; + assert (!surface->finished); + /* move image_rect into backend device coords (opposite of acquire_dest_image) */ + image_rect->x = BACKEND_X(surface, image_rect->x); + image_rect->y = BACKEND_Y(surface, image_rect->y); + + if (interest_rect) { + dev_interest_rect = *interest_rect; + dev_interest_rect.x = BACKEND_X(surface, dev_interest_rect.x); + dev_interest_rect.y = BACKEND_Y(surface, dev_interest_rect.y); + } + if (surface->backend->release_dest_image) - surface->backend->release_dest_image (surface, interest_rect, + surface->backend->release_dest_image (surface, &dev_interest_rect, image, image_rect, image_extra); } @@ -724,6 +791,13 @@ return CAIRO_INT_STATUS_UNSUPPORTED; status = surface->backend->clone_similar (surface, src, clone_out); + if (status == CAIRO_STATUS_SUCCESS) { + (*clone_out)->device_x_offset = src->device_x_offset; + (*clone_out)->device_y_offset = src->device_y_offset; + (*clone_out)->device_x_scale = src->device_x_scale; + (*clone_out)->device_y_scale = src->device_y_scale; + } + if (status != CAIRO_INT_STATUS_UNSUPPORTED) return status; @@ -732,6 +806,12 @@ return status; status = surface->backend->clone_similar (surface, &image->base, clone_out); + if (status == CAIRO_STATUS_SUCCESS) { + (*clone_out)->device_x_offset = src->device_x_offset; + (*clone_out)->device_y_offset = src->device_y_offset; + (*clone_out)->device_x_scale = src->device_x_scale; + (*clone_out)->device_y_scale = src->device_y_scale; + } /* If the above failed point, we could implement a full fallback * using acquire_dest_image, but that's going to be very @@ -804,11 +884,29 @@ return CAIRO_STATUS_SURFACE_FINISHED; if (dst->backend->composite) { + int backend_src_x = src_x; + int backend_src_y = src_y; + int backend_mask_x = mask_x; + int backend_mask_y = mask_y; + + if (src->type == CAIRO_PATTERN_SURFACE) { + cairo_surface_t *src_surface = ((cairo_surface_pattern_t*)src)->surface; + backend_src_x = BACKEND_X(src_surface, src_x); + backend_src_y = BACKEND_Y(src_surface, src_y); + } + + if (mask && mask->type == CAIRO_PATTERN_SURFACE) { + cairo_surface_t *mask_surface = ((cairo_surface_pattern_t*)mask)->surface; + backend_mask_x = BACKEND_X(mask_surface, mask_x); + backend_mask_y = BACKEND_Y(mask_surface, mask_y); + } + status = dst->backend->composite (op, src, mask, dst, - src_x, src_y, - mask_x, mask_y, - dst_x, dst_y, + backend_src_x, backend_src_y, + backend_mask_x, backend_mask_y, + BACKEND_X(dst, dst_x), + BACKEND_Y(dst, dst_y), width, height); if (status != CAIRO_INT_STATUS_UNSUPPORTED) return status; @@ -937,6 +1035,8 @@ int num_rects) { cairo_int_status_t status; + cairo_rectangle_t *dev_rects = NULL; + int i; assert (! surface->is_snapshot); @@ -950,8 +1050,26 @@ return CAIRO_STATUS_SUCCESS; if (surface->backend->fill_rectangles) { - status = surface->backend->fill_rectangles (surface, op, color, - rects, num_rects); + if (surface->device_x_offset != 0.0 || + surface->device_y_offset != 0.0 || + surface->device_x_scale != 1.0 || + surface->device_y_scale != 1.0) + { + dev_rects = malloc(sizeof(cairo_rectangle_t) * num_rects); + for (i = 0; i < num_rects; i++) { + dev_rects[i].x = BACKEND_X(surface, rects[i].x); + dev_rects[i].y = BACKEND_Y(surface, rects[i].y); + + dev_rects[i].width = BACKEND_X_SIZE(surface, rects[i].width); + dev_rects[i].height = BACKEND_Y_SIZE(surface, rects[i].height); + } + } + + status = surface->backend->fill_rectangles (surface, + op, + color, + dev_rects ? dev_rects : rects, num_rects); + free (dev_rects); if (status != CAIRO_INT_STATUS_UNSUPPORTED) return status; } @@ -1012,10 +1130,31 @@ if (surface->backend->stroke) { cairo_status_t status; + cairo_path_fixed_t *dev_path = path; + cairo_path_fixed_t real_dev_path; + + if (surface->device_x_offset != 0.0 || + surface->device_y_offset != 0.0 || + surface->device_x_scale != 1.0 || + surface->device_y_scale != 1.0) + { + _cairo_path_fixed_init_copy (&real_dev_path, path); + _cairo_path_fixed_offset_and_scale (&real_dev_path, + _cairo_fixed_from_double (surface->device_x_offset), + _cairo_fixed_from_double (surface->device_y_offset), + _cairo_fixed_from_double (surface->device_x_scale), + _cairo_fixed_from_double (surface->device_y_scale)); + dev_path = &real_dev_path; + } + status = surface->backend->stroke (surface, op, source, - path, stroke_style, + dev_path, stroke_style, ctm, ctm_inverse, tolerance, antialias); + + if (dev_path == &real_dev_path) + _cairo_path_fixed_fini (&real_dev_path); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) return status; } @@ -1036,13 +1175,33 @@ cairo_antialias_t antialias) { cairo_status_t status; + cairo_path_fixed_t *dev_path = path; + cairo_path_fixed_t real_dev_path; assert (! surface->is_snapshot); if (surface->backend->fill) { + if (surface->device_x_offset != 0.0 || + surface->device_y_offset != 0.0 || + surface->device_x_scale != 1.0 || + surface->device_y_scale != 1.0) + { + _cairo_path_fixed_init_copy (&real_dev_path, path); + _cairo_path_fixed_offset_and_scale (&real_dev_path, + _cairo_fixed_from_double (surface->device_x_offset), + _cairo_fixed_from_double (surface->device_y_offset), + _cairo_fixed_from_double (surface->device_x_scale), + _cairo_fixed_from_double (surface->device_y_scale)); + dev_path = &real_dev_path; + } + status = surface->backend->fill (surface, op, source, - path, fill_rule, + dev_path, fill_rule, tolerance, antialias); + + if (dev_path == &real_dev_path) + _cairo_path_fixed_fini (&real_dev_path); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) return status; } @@ -1067,6 +1226,7 @@ int num_traps) { cairo_int_status_t status; + cairo_trapezoid_t *dev_traps = NULL; assert (! dst->is_snapshot); @@ -1082,13 +1242,36 @@ return CAIRO_STATUS_SURFACE_FINISHED; if (dst->backend->composite_trapezoids) { + if (dst->device_x_offset != 0.0 || + dst->device_y_offset != 0.0 || + dst->device_x_scale != 1.0 || + dst->device_y_scale != 1.0) + { + dev_traps = malloc (sizeof (cairo_trapezoid_t) * num_traps); + if (!dev_traps) + return CAIRO_STATUS_NO_MEMORY; + + _cairo_trapezoid_array_translate_and_scale + (dev_traps, traps, num_traps, + dst->device_x_offset, + dst->device_y_offset, + dst->device_x_scale, + dst->device_y_scale); + } + + status = dst->backend->composite_trapezoids (op, pattern, dst, antialias, src_x, src_y, - dst_x, dst_y, + BACKEND_X(dst, dst_x), + BACKEND_Y(dst, dst_y), + // XXX what the heck do I do with width/height? + // they're not the same for src and dst! width, height, - traps, num_traps); + dev_traps ? dev_traps : traps, num_traps); + free (dev_traps); + if (status != CAIRO_INT_STATUS_UNSUPPORTED) return status; } @@ -1235,6 +1418,9 @@ pixman_region16_t *region, unsigned int serial) { + pixman_region16_t *dev_region = NULL; + cairo_status_t status; + if (surface->status) return surface->status; @@ -1242,10 +1428,50 @@ return CAIRO_STATUS_SURFACE_FINISHED; assert (surface->backend->set_clip_region != NULL); - + + if (surface->device_x_offset != 0.0 || + surface->device_y_offset != 0.0 || + surface->device_x_scale != 1.0 || + surface->device_y_scale != 1.0) + { + dev_region = pixman_region_create (); + if (surface->device_x_scale == 1.0 && + surface->device_y_scale == 1.0) + { + pixman_region_copy (dev_region, region); + pixman_region_translate (dev_region, surface->device_x_offset, surface->device_y_offset); + } else { + int i, nr = pixman_region_num_rects (region); + pixman_box16_t *rects = pixman_region_rects (region); + for (i = 0; i < nr; i++) { + pixman_box16_t tmpb; + pixman_region16_t *tmpr; + + tmpb.x1 = BACKEND_X(surface, rects[i].x1); + tmpb.y1 = BACKEND_Y(surface, rects[i].y1); + tmpb.x2 = BACKEND_X(surface, rects[i].x2); + tmpb.y2 = BACKEND_Y(surface, rects[i].y2); + + tmpr = pixman_region_create_simple (&tmpb); + + pixman_region_append (dev_region, tmpr); + pixman_region_destroy (tmpr); + } + + pixman_region_validate (dev_region, &i); + } + + region = dev_region; + } + surface->current_clip_serial = serial; - return surface->backend->set_clip_region (surface, region); + status = surface->backend->set_clip_region (surface, region); + + if (dev_region) + pixman_region_destroy (dev_region); + + return status; } cairo_int_status_t @@ -1255,6 +1481,10 @@ double tolerance, cairo_antialias_t antialias) { + cairo_path_fixed_t *dev_path = path; + cairo_path_fixed_t real_dev_path; + cairo_status_t status; + if (surface->status) return surface->status; @@ -1263,11 +1493,30 @@ assert (surface->backend->intersect_clip_path != NULL); - return surface->backend->intersect_clip_path (surface, - path, - fill_rule, - tolerance, - antialias); + if (surface->device_x_offset != 0.0 || + surface->device_y_offset != 0.0 || + surface->device_x_scale != 1.0 || + surface->device_y_scale != 1.0) + { + _cairo_path_fixed_init_copy (&real_dev_path, path); + _cairo_path_fixed_offset_and_scale (&real_dev_path, + _cairo_fixed_from_double (surface->device_x_offset), + _cairo_fixed_from_double (surface->device_y_offset), + _cairo_fixed_from_double (surface->device_x_scale), + _cairo_fixed_from_double (surface->device_y_scale)); + dev_path = &real_dev_path; + } + + status = surface->backend->intersect_clip_path (surface, + dev_path, + fill_rule, + tolerance, + antialias); + + if (dev_path == &real_dev_path) + _cairo_path_fixed_fini (&real_dev_path); + + return status; } static cairo_status_t @@ -1283,11 +1532,11 @@ if (status) return status; - return surface->backend->intersect_clip_path (surface, - &clip_path->path, - clip_path->fill_rule, - clip_path->tolerance, - clip_path->antialias); + return _cairo_surface_intersect_clip_path (surface, + &clip_path->path, + clip_path->fill_rule, + clip_path->tolerance, + clip_path->antialias); } /** @@ -1390,13 +1639,20 @@ _cairo_surface_get_extents (cairo_surface_t *surface, cairo_rectangle_t *rectangle) { + cairo_status_t status; + if (surface->status) return surface->status; if (surface->finished) return CAIRO_STATUS_SURFACE_FINISHED; - return surface->backend->get_extents (surface, rectangle); + status = surface->backend->get_extents (surface, rectangle); + + rectangle->x = SURFACE_X(surface, rectangle->x); + rectangle->y = SURFACE_Y(surface, rectangle->y); + + return status; } cairo_status_t @@ -1408,13 +1664,34 @@ cairo_scaled_font_t *scaled_font) { cairo_status_t status; + cairo_glyph_t *dev_glyphs = NULL; assert (! surface->is_snapshot); if (surface->backend->show_glyphs) { + if (surface->device_x_offset != 0.0 || + surface->device_y_offset != 0.0 || + surface->device_x_scale != 1.0 || + surface->device_y_scale != 1.0) + { + int i; + + dev_glyphs = malloc (sizeof(cairo_glyph_t) * num_glyphs); + if (!dev_glyphs) + return CAIRO_STATUS_NO_MEMORY; + + for (i = 0; i < num_glyphs; i++) { + dev_glyphs[i].index = glyphs[i].index; + // err, we really should scale the size of the glyphs, no? + dev_glyphs[i].x = BACKEND_X(surface, glyphs[i].x); + dev_glyphs[i].y = BACKEND_Y(surface, glyphs[i].y); + } + } + status = surface->backend->show_glyphs (surface, op, source, - glyphs, num_glyphs, - scaled_font); + dev_glyphs ? dev_glyphs : glyphs, + num_glyphs, scaled_font); + free (dev_glyphs); if (status != CAIRO_INT_STATUS_UNSUPPORTED) return status; } @@ -1444,6 +1721,7 @@ int num_glyphs) { cairo_status_t status; + cairo_glyph_t *dev_glyphs = NULL; assert (! dst->is_snapshot); @@ -1453,14 +1731,35 @@ if (dst->finished) return CAIRO_STATUS_SURFACE_FINISHED; - if (dst->backend->old_show_glyphs) + if (dst->backend->old_show_glyphs) { + if (dst->device_x_offset != 0.0 || + dst->device_y_offset != 0.0 || + dst->device_x_scale != 1.0 || + dst->device_y_scale != 1.0) + { + int i; + + dev_glyphs = malloc(sizeof(cairo_glyph_t) * num_glyphs); + for (i = 0; i < num_glyphs; i++) { + dev_glyphs[i] = glyphs[i]; + // err, we really should scale the size of the glyphs, no? + dev_glyphs[i].x = BACKEND_X(dst, dev_glyphs[i].x); + dev_glyphs[i].y = BACKEND_Y(dst, dev_glyphs[i].y); + } + + glyphs = dev_glyphs; + } + status = dst->backend->old_show_glyphs (scaled_font, op, pattern, dst, source_x, source_y, - dest_x, dest_y, + BACKEND_X(dst, dest_x), + BACKEND_Y(dst, dest_y), width, height, glyphs, num_glyphs); - else + + free (dev_glyphs); + } else status = CAIRO_INT_STATUS_UNSUPPORTED; return status; @@ -1570,7 +1869,15 @@ cairo_rectangle_t *mask_rectangle = NULL; assert (! dst->is_snapshot); - + + /* This is a little odd; this function is called from the xlib/image surfaces, + * where the coordinates have already been transformed by the device_xy_offset. + * We need to undo this before running through this function, + * otherwise those offsets get applied twice. + */ + dst_x = SURFACE_X(dst, dst_x); + dst_y = SURFACE_Y(dst, dst_y); + /* The RENDER/libpixman operators are clipped to the bounds of the untransformed, * non-repeating sources and masks. Other sources and masks can be ignored. */ @@ -1645,6 +1952,10 @@ cairo_rectangle_t *mask_rectangle = NULL; assert (! dst->is_snapshot); + + /* See comment at start of _cairo_surface_composite_fixup_unbounded */ + dst_x = SURFACE_X(dst, dst_x); + dst_y = SURFACE_Y(dst, dst_y); /* The RENDER/libpixman operators are clipped to the bounds of the untransformed, * non-repeating sources and masks. Other sources and masks can be ignored. Index: src/cairo-traps.c =================================================================== --- src/cairo-traps.c.orig 2006-02-10 11:20:53.192500000 -0800 +++ src/cairo-traps.c 2006-02-10 11:30:54.375000000 -0800 @@ -258,6 +258,54 @@ } } +void +_cairo_trapezoid_array_translate_and_scale (cairo_trapezoid_t *offset_traps, + cairo_trapezoid_t *src_traps, + int num_traps, + double tx, double ty, + double sx, double sy) +{ + int i; + cairo_fixed_t xoff = _cairo_fixed_from_double (tx); + cairo_fixed_t yoff = _cairo_fixed_from_double (ty); + + if (sx == 1.0 && sy == 1.0) { + for (i = 0; i < num_traps; i++) { + offset_traps[i].top = src_traps[i].top + yoff; + offset_traps[i].bottom = src_traps[i].bottom + yoff; + offset_traps[i].left.p1.x = src_traps[i].left.p1.x + xoff; + offset_traps[i].left.p1.y = src_traps[i].left.p1.y + yoff; + offset_traps[i].left.p2.x = src_traps[i].left.p2.x + xoff; + offset_traps[i].left.p2.y = src_traps[i].left.p2.y + yoff; + offset_traps[i].right.p1.x = src_traps[i].right.p1.x + xoff; + offset_traps[i].right.p1.y = src_traps[i].right.p1.y + yoff; + offset_traps[i].right.p2.x = src_traps[i].right.p2.x + xoff; + offset_traps[i].right.p2.y = src_traps[i].right.p2.y + yoff; + } + } else { + cairo_fixed_t xsc = _cairo_fixed_from_double (sx); + cairo_fixed_t ysc = _cairo_fixed_from_double (sy); + + for (i = 0; i < num_traps; i++) { +#define FIXED_MUL(_a, _b) \ + (_cairo_int64_to_int32(_cairo_int64_rsl(_cairo_int32x32_64_mul((_a), (_b)), 16))) + + offset_traps[i].top = FIXED_MUL(src_traps[i].top + yoff, ysc); + offset_traps[i].bottom = FIXED_MUL(src_traps[i].bottom + yoff, ysc); + offset_traps[i].left.p1.x = FIXED_MUL(src_traps[i].left.p1.x + xoff, xsc); + offset_traps[i].left.p1.y = FIXED_MUL(src_traps[i].left.p1.y + yoff, ysc); + offset_traps[i].left.p2.x = FIXED_MUL(src_traps[i].left.p2.x + xoff, xsc); + offset_traps[i].left.p2.y = FIXED_MUL(src_traps[i].left.p2.y + yoff, ysc); + offset_traps[i].right.p1.x = FIXED_MUL(src_traps[i].right.p1.x + xoff, xsc); + offset_traps[i].right.p1.y = FIXED_MUL(src_traps[i].right.p1.y + yoff, ysc); + offset_traps[i].right.p2.x = FIXED_MUL(src_traps[i].right.p2.x + xoff, xsc); + offset_traps[i].right.p2.y = FIXED_MUL(src_traps[i].right.p2.y + yoff, ysc); + +#undef FIXED_MUL + } + } +} + cairo_status_t _cairo_traps_tessellate_triangle (cairo_traps_t *traps, cairo_point_t t[3]) { @@ -859,4 +907,3 @@ return CAIRO_STATUS_SUCCESS; } - Index: src/cairoint.h =================================================================== --- src/cairoint.h.orig 2006-02-10 11:20:53.195500000 -0800 +++ src/cairoint.h 2006-02-10 14:05:49.896625000 -0800 @@ -1466,6 +1466,13 @@ double *x1, double *y1, double *x2, double *y2); +cairo_private void +_cairo_path_fixed_offset_and_scale (cairo_path_fixed_t *path, + cairo_fixed_t offx, + cairo_fixed_t offy, + cairo_fixed_t scalex, + cairo_fixed_t scaley); + /* cairo_path_fill.c */ cairo_private cairo_status_t _cairo_path_fixed_fill_to_traps (cairo_path_fixed_t *path, @@ -1996,6 +2003,13 @@ _cairo_traps_extract_region (cairo_traps_t *tr, pixman_region16_t **region); +cairo_private void +_cairo_trapezoid_array_translate_and_scale (cairo_trapezoid_t *offset_traps, + cairo_trapezoid_t *src_traps, + int num_traps, + double tx, double ty, + double sx, double sy); + /* cairo_slope.c */ cairo_private void _cairo_slope_init (cairo_slope_t *slope, cairo_point_t *a, cairo_point_t *b); Index: test/buffer-diff.c =================================================================== --- test/buffer-diff.c.orig 2006-02-10 11:20:53.204500000 -0800 +++ test/buffer-diff.c 2006-02-10 11:30:54.390625000 -0800 @@ -62,7 +62,9 @@ unsigned char *_buf_diff, int width, int height, - int stride, + int stride_a, + int stride_b, + int stride_diff, pixman_bits_t mask) { int x, y; @@ -72,12 +74,14 @@ pixman_bits_t *buf_b = (pixman_bits_t*)_buf_b; pixman_bits_t *buf_diff = (pixman_bits_t*)_buf_diff; - stride /= sizeof(pixman_bits_t); + stride_a /= sizeof(pixman_bits_t); + stride_b /= sizeof(pixman_bits_t); + stride_diff /= sizeof(pixman_bits_t); for (y = 0; y < height; y++) { - row_a = buf_a + y * stride; - row_b = buf_b + y * stride; - row = buf_diff + y * stride; + row_a = buf_a + y * stride_a; + row_b = buf_b + y * stride_b; + row = buf_diff + y * stride_diff; for (x = 0; x < width; x++) { /* check if the pixels are the same */ @@ -112,9 +116,12 @@ unsigned char *buf_diff, int width, int height, - int stride) + int stride_a, + int stride_b, + int stride_diff) { - return buffer_diff_core(buf_a, buf_b, buf_diff, width, height, stride, 0xffffffff); + return buffer_diff_core(buf_a, buf_b, buf_diff, + width, height, stride_a, stride_b, stride_diff, 0xffffffff); } int @@ -123,9 +130,12 @@ unsigned char *buf_diff, int width, int height, - int stride) + int stride_a, + int stride_b, + int stride_diff) { - return buffer_diff_core(buf_a, buf_b, buf_diff, width, height, stride, 0x00ffffff); + return buffer_diff_core(buf_a, buf_b, buf_diff, + width, height, stride_a, stride_b, stride_diff, 0x00ffffff); } /* Image comparison code courtesy of Richard Worth @@ -136,11 +146,16 @@ int image_diff (const char *filename_a, const char *filename_b, - const char *filename_diff) + const char *filename_diff, + int ax, + int ay, + int bx, + int by) { int pixels_changed; unsigned int width_a, height_a, stride_a; unsigned int width_b, height_b, stride_b; + unsigned int stride_diff; unsigned char *buf_a, *buf_b, *buf_diff; read_png_status_t status; @@ -154,9 +169,13 @@ return -1; } + width_a -= ax; + height_a -= ay; + width_b -= bx; + height_b -= by; + if (width_a != width_b || - height_a != height_b || - stride_a != stride_b) + height_a != height_b) { cairo_test_log ("Error: Image size mismatch: (%dx%d@%d) vs. (%dx%d@%d)\n" " for %s vs. %s\n", @@ -168,17 +187,27 @@ return -1; } - buf_diff = xcalloc (stride_a * height_a, 1); + stride_diff = 4 * width_a; + buf_diff = xcalloc (stride_diff * height_a, 1); - pixels_changed = buffer_diff (buf_a, buf_b, buf_diff, - width_a, height_a, stride_a); + pixels_changed = buffer_diff (buf_a + (ay * stride_a) + ax * 4, + buf_b + (by * stride_b) + by * 4, + buf_diff, + width_a, height_a, + stride_a, stride_b, stride_diff); if (pixels_changed) { - FILE *png_file = fopen (filename_diff, "wb"); - write_png_argb32 (buf_diff, png_file, width_a, height_a, stride_a); - fclose (png_file); + FILE *png_file; + if (filename_diff) + png_file = fopen (filename_diff, "wb"); + else + png_file = stdout; + write_png_argb32 (buf_diff, png_file, width_a, height_a, stride_diff); + if (png_file != stdout) + fclose (png_file); } else { - xunlink (filename_diff); + if (filename_diff) + xunlink (filename_diff); } free (buf_a); @@ -204,7 +233,11 @@ int image_diff_flattened (const char *filename_a, const char *filename_b, - const char *filename_diff) + const char *filename_diff, + int ax, + int ay, + int bx, + int by) { int pixels_changed; unsigned int width_a, height_a, stride_a; @@ -225,6 +258,11 @@ return -1; } + width_a -= ax; + height_a -= ay; + width_b -= bx; + height_b -= by; + if (width_a != width_b || height_a != height_b || stride_a != stride_b) @@ -252,6 +290,8 @@ CAIRO_FORMAT_ARGB32, width_b, height_b, stride_b); + cairo_surface_set_device_offset (b_flat_surface, -bx, -by); + cr = cairo_create (b_flat_surface); cairo_set_source_rgb (cr, 1, 1, 1); @@ -263,8 +303,11 @@ cairo_surface_destroy (b_flat_surface); cairo_surface_destroy (buf_b_surface); - pixels_changed = buffer_diff (buf_a, b_flat, buf_diff, - width_a, height_a, stride_a); + pixels_changed = buffer_diff (buf_a + (ay * stride_a) + ax * 4, + b_flat, + buf_diff, + width_a, height_a, + width_a, height_a, stride_a); if (pixels_changed) { FILE *png_file = fopen (filename_diff, "wb"); Index: test/buffer-diff.h =================================================================== --- test/buffer-diff.h.orig 2006-02-10 11:20:53.212500000 -0800 +++ test/buffer-diff.h 2006-02-10 11:30:54.390625000 -0800 @@ -36,7 +36,9 @@ unsigned char *buf_diff, int width, int height, - int stride); + int stride_a, + int stride_b, + int stride_diff); /* Returns number of pixels changed ignoring the alpha channel. * Also fills in a "diff" buffer intended to visually show where the @@ -48,7 +50,10 @@ unsigned char *buf_diff, int width, int height, - int stride); + int stride_a, + int stride_b, + int stride_diff); + /* Returns number of pixels changed, (or -1 on error). * Also saves a "diff" image intended to visually show where the @@ -57,13 +62,21 @@ int image_diff (const char *filename_a, const char *filename_b, - const char *filename_diff); + const char *filename_diff, + int ax, + int ay, + int bx, + int by); /* Like image_diff, but blending the contents of b over white first. */ int image_diff_flattened (const char *filename_a, const char *filename_b, - const char *filename_diff); + const char *filename_diff, + int ax, + int ay, + int bx, + int by); #endif Index: test/cairo-test.c =================================================================== --- test/cairo-test.c.orig 2006-02-10 11:20:53.217500000 -0800 +++ test/cairo-test.c 2006-02-10 11:30:54.421875000 -0800 @@ -61,6 +61,8 @@ #define CAIRO_TEST_REF_SUFFIX "-ref.png" #define CAIRO_TEST_DIFF_SUFFIX "-diff.png" +#define NUM_DEVICE_OFFSETS 2 + /* A fake format we use for the flattened ARGB output of the PS and * PDF surfaces. */ #define CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED -1 @@ -1345,12 +1347,13 @@ static cairo_test_status_t cairo_test_for_target (cairo_test_t *test, cairo_test_draw_function_t draw, - cairo_test_target_t *target) + cairo_test_target_t *target, + int dev_offset) { cairo_test_status_t status; cairo_surface_t *surface; cairo_t *cr; - char *png_name, *ref_name, *diff_name; + char *png_name, *ref_name, *diff_name, *offset_str; char *srcdir; char *format; cairo_test_status_t ret; @@ -1361,8 +1364,13 @@ srcdir = "."; format = _cairo_test_content_name (target->content); - xasprintf (&png_name, "%s-%s-%s%s", test->name, - target->name, format, CAIRO_TEST_PNG_SUFFIX); + if (dev_offset) + xasprintf (&offset_str, "-%d", dev_offset); + else + offset_str = strdup(""); + + xasprintf (&png_name, "%s-%s-%s%s%s", test->name, + target->name, format, offset_str, CAIRO_TEST_PNG_SUFFIX); xasprintf (&ref_name, "%s/%s-%s-%s%s", srcdir, test->name, target->name, format, CAIRO_TEST_REF_SUFFIX); if (access (ref_name, F_OK) != 0) { @@ -1376,17 +1384,30 @@ xasprintf (&ref_name, "%s/%s-%s%s", srcdir, test->name, format,CAIRO_TEST_REF_SUFFIX); } - xasprintf (&diff_name, "%s-%s-%s%s", test->name, - target->name, format, CAIRO_TEST_DIFF_SUFFIX); + xasprintf (&diff_name, "%s-%s-%s%s%s", test->name, + target->name, format, offset_str, CAIRO_TEST_DIFF_SUFFIX); /* Run the actual drawing code. */ + if (test->width && test->height) { + test->width += dev_offset; + test->height += dev_offset; + } + surface = (target->create_target_surface) (test, target->content, &target->closure); + + if (test->width && test->height) { + test->width -= dev_offset; + test->height -= dev_offset;; + } + if (surface == NULL) { cairo_test_log ("Error: Failed to set %s target\n", target->name); ret = CAIRO_TEST_UNTESTED; goto UNWIND_STRINGS; } + cairo_surface_set_device_offset (surface, dev_offset, dev_offset); + cr = cairo_create (surface); /* Clear to transparent (or black) depending on whether the target @@ -1420,9 +1441,9 @@ int pixels_changed; (target->write_to_png) (surface, png_name); if (target->content == CAIRO_TEST_CONTENT_COLOR_ALPHA_FLATTENED) - pixels_changed = image_diff_flattened (png_name, ref_name, diff_name); + pixels_changed = image_diff_flattened (png_name, ref_name, diff_name, dev_offset, dev_offset, 0, 0); else - pixels_changed = image_diff (png_name, ref_name, diff_name); + pixels_changed = image_diff (png_name, ref_name, diff_name, dev_offset, dev_offset, 0, 0); if (pixels_changed) { if (pixels_changed > 0) cairo_test_log ("Error: %d pixels differ from reference image %s\n", @@ -1447,6 +1468,7 @@ free (png_name); free (ref_name); free (diff_name); + free (offset_str); return ret; } @@ -1455,7 +1477,7 @@ cairo_test_expecting (cairo_test_t *test, cairo_test_draw_function_t draw, cairo_test_status_t expectation) { - int i, num_targets; + int i, j, num_targets; const char *tname; cairo_test_status_t status, ret; cairo_test_target_t **targets_to_test; @@ -1599,39 +1621,45 @@ */ ret = CAIRO_TEST_UNTESTED; for (i = 0; i < num_targets; i++) { - cairo_test_target_t *target = targets_to_test[i]; - cairo_test_log ("Testing %s with %s target\n", test->name, target->name); - printf ("%s-%s-%s:\t", test->name, target->name, - _cairo_test_content_name (target->content)); - - status = cairo_test_for_target (test, draw, target); - - cairo_test_log ("TEST: %s TARGET: %s FORMAT: %s RESULT: ", - test->name, target->name, - _cairo_test_content_name (target->content)); - - switch (status) { - case CAIRO_TEST_SUCCESS: - printf ("PASS\n"); - cairo_test_log ("PASS\n"); - if (ret == CAIRO_TEST_UNTESTED) - ret = CAIRO_TEST_SUCCESS; - break; - case CAIRO_TEST_UNTESTED: - printf ("UNTESTED\n"); - cairo_test_log ("UNTESTED\n"); - break; - default: - case CAIRO_TEST_FAILURE: - if (expectation == CAIRO_TEST_FAILURE) { - printf ("XFAIL\n"); - cairo_test_log ("XFAIL\n"); - } else { - printf ("FAIL\n"); - cairo_test_log ("FAIL\n"); + for (j = 0; j < NUM_DEVICE_OFFSETS; j++) { + cairo_test_target_t *target = targets_to_test[i]; + int dev_offset = j * 25; + + cairo_test_log ("Testing %s with %s target (dev offset %d)\n", test->name, target->name, dev_offset); + printf ("%s-%s-%s [%d]:\t", test->name, target->name, + _cairo_test_content_name (target->content), + dev_offset); + + status = cairo_test_for_target (test, draw, target, dev_offset); + + cairo_test_log ("TEST: %s TARGET: %s FORMAT: %s OFFSET: %d RESULT: ", + test->name, target->name, + _cairo_test_content_name (target->content), + dev_offset); + + switch (status) { + case CAIRO_TEST_SUCCESS: + printf ("PASS\n"); + cairo_test_log ("PASS\n"); + if (ret == CAIRO_TEST_UNTESTED) + ret = CAIRO_TEST_SUCCESS; + break; + case CAIRO_TEST_UNTESTED: + printf ("UNTESTED\n"); + cairo_test_log ("UNTESTED\n"); + break; + default: + case CAIRO_TEST_FAILURE: + if (expectation == CAIRO_TEST_FAILURE) { + printf ("XFAIL\n"); + cairo_test_log ("XFAIL\n"); + } else { + printf ("FAIL\n"); + cairo_test_log ("FAIL\n"); + } + ret = status; + break; } - ret = status; - break; } } if (ret == CAIRO_TEST_UNTESTED) Index: test/imagediff.c =================================================================== --- test/imagediff.c.orig 2006-02-10 11:20:53.225500000 -0800 +++ test/imagediff.c 2006-02-10 11:30:54.421875000 -0800 @@ -34,48 +34,31 @@ int main (int argc, char *argv[]) { - unsigned char *buffer_a; - unsigned int width_a, height_a, stride_a; - unsigned char *buffer_b; - unsigned int width_b, height_b, stride_b; - - unsigned char *buffer; - unsigned int width, height, stride; - int buffer_size, total_pixels_changed; + int total_pixels_changed; - if (argc < 2) { - fprintf (stderr, "Usage: %s image1.png image2.png\n", argv[0]); + unsigned int ax, ay, bx, by; + + if (argc != 3 && argc != 7) { + fprintf (stderr, "Usage: %s image1.png image2.png [ax ay bx by]\n", argv[0]); fprintf (stderr, "Computes an output image designed to present a \"visual diff\" such that even\n"); fprintf (stderr, "small errors in single pixels are readily apparent in the output.\n"); fprintf (stderr, "The output image is written on stdout.\n"); exit (1); } - read_png_argb32 (argv[1], &buffer_a, &width_a, &height_a, &stride_a); - read_png_argb32 (argv[2], &buffer_b, &width_b, &height_b, &stride_b); - - if ((width_a == width_b) && (height_a == height_b) && (stride_a == stride_b)) - { - width = width_a; - height = height_a; - stride = stride_a; + if (argc == 7) { + ax = strtoul (argv[3], NULL, 0); + ay = strtoul (argv[4], NULL, 0); + bx = strtoul (argv[5], NULL, 0); + by = strtoul (argv[6], NULL, 0); } else { - fprintf (stderr, "Error. Both images must be the same size\n"); - return 1; + ax = ay = bx = by = 0; } - buffer_size = stride * height; - buffer = xmalloc (buffer_size); - - total_pixels_changed = buffer_diff (buffer_a, buffer_b, buffer, - width_a, height_a, stride_a); - + total_pixels_changed = image_diff (argv[1], argv[2], NULL, ax, ay, bx, by); if (total_pixels_changed) fprintf (stderr, "Total pixels changed: %d\n", total_pixels_changed); - write_png_argb32 (buffer, stdout, width, height, stride); - - free (buffer); return total_pixels_changed; } Index: test/xlib-surface.c =================================================================== --- test/xlib-surface.c.orig 2006-02-10 11:20:53.229500000 -0800 +++ test/xlib-surface.c 2006-02-10 11:30:54.421875000 -0800 @@ -160,6 +160,8 @@ diff_data + offset, SIZE - OFFSCREEN_OFFSET, SIZE - OFFSCREEN_OFFSET, + 4 * SIZE, + 4 * SIZE, 4 * SIZE); } else { result = !buffer_diff_noalpha (reference_data, @@ -167,6 +169,8 @@ diff_data, SIZE, SIZE, + 4 * SIZE, + 4 * SIZE, 4 * SIZE); }