diff options
Diffstat (limited to 'src/cairo-surface.c')
-rw-r--r-- | src/cairo-surface.c | 329 |
1 files changed, 312 insertions, 17 deletions
diff --git a/src/cairo-surface.c b/src/cairo-surface.c index 11fbc60..8353d32 100644 --- a/src/cairo-surface.c +++ b/src/cairo-surface.c @@ -245,18 +245,38 @@ _cairo_surface_get_clip_mode (cairo_surface_t *surface) return CAIRO_CLIP_MODE_MASK; } -void +/** + * cairo_surface_reference: + * @surface: a #cairo_surface_t + * + * Increases the reference count on @surface by one. This prevents + * @surface from being destroyed until a matching call to + * cairo_surface_destroy() is made. + * + * Return value: the referenced #cairo_surface_t. + **/ +cairo_surface_t * cairo_surface_reference (cairo_surface_t *surface) { if (surface == NULL) - return; + return NULL; if (surface->ref_count == (unsigned int)-1) - return; + return surface; surface->ref_count++; + + return surface; } +/** + * cairo_surface_destroy: + * @surface: a #cairo_t + * + * Decreases the reference count on @surface by one. If the result is + * zero, then @surface and all associated resources are freed. See + * cairo_surface_reference(). + **/ void cairo_surface_destroy (cairo_surface_t *surface) { @@ -310,7 +330,15 @@ cairo_surface_finish (cairo_surface_t *surface) surface->finished = TRUE; return; } - + + if (!surface->status && surface->backend->flush) { + status = surface->backend->flush (surface); + if (status) { + _cairo_surface_set_error (surface, status); + return; + } + } + status = surface->backend->finish (surface); if (status) { _cairo_surface_set_error (surface, status); @@ -393,6 +421,93 @@ cairo_surface_get_font_options (cairo_surface_t *surface, } /** + * cairo_surface_flush: + * @surface: a #cairo_surface_t + * + * Do any pending drawing for the surface and also restore any + * temporary modification's cairo has made to the surface's + * state. This function must be called before switching from + * drawing on the surface with cairo to drawing on it directly + * with native APIs. If the surface doesn't support direct access, + * then this function does nothing. + **/ +void +cairo_surface_flush (cairo_surface_t *surface) +{ + if (surface->status) { + _cairo_surface_set_error (surface, surface->status); + return; + } + + if (surface->finished) { + _cairo_surface_set_error (surface, CAIRO_STATUS_SURFACE_FINISHED); + return; + } + + if (surface->backend->flush) { + cairo_status_t status; + + status = surface->backend->flush (surface); + + if (status) + _cairo_surface_set_error (surface, status); + } +} + +/** + * cairo_surface_mark_dirty: + * @surface: a #cairo_surface_t + * + * Tells cairo that drawing has been done to surface using means other + * than cairo, and that cairo should reread any cached areas. Note + * that you must call cairo_surface_flush() before doing such drawing. + */ +void +cairo_surface_mark_dirty (cairo_surface_t *surface) +{ + cairo_surface_mark_dirty_rectangle (surface, 0, 0, -1, -1); +} + +/** + * cairo_surface_mark_dirty_rectangle: + * @surface: a #cairo_surface_t + * @x: X coordinate of dirty rectangle + * @y: Y coordinate of dirty rectangle + * @width: width of dirty rectangle + * @height: height of dirty rectangle + * + * Like cairo_surface_mark_dirty(), but drawing has been done only to + * the specified rectangle, so that cairo can retain cached contents + * for other parts of the surface. + */ +void +cairo_surface_mark_dirty_rectangle (cairo_surface_t *surface, + int x, + int y, + int width, + int height) +{ + if (surface->status) { + _cairo_surface_set_error (surface, surface->status); + return; + } + + if (surface->finished) { + _cairo_surface_set_error (surface, CAIRO_STATUS_SURFACE_FINISHED); + return; + } + + if (surface->backend->mark_dirty_rectangle) { + cairo_status_t status; + + status = surface->backend->mark_dirty_rectangle (surface, x, y, width, height); + + if (status) + _cairo_surface_set_error (surface, status); + } +} + +/** * cairo_surface_set_device_offset: * @surface: a #cairo_surface_t * @x_offset: the offset in the X direction, in device units @@ -876,6 +991,7 @@ static cairo_status_t _fallback_composite_trapezoids (cairo_operator_t operator, cairo_pattern_t *pattern, cairo_surface_t *dst, + cairo_antialias_t antialias, int src_x, int src_y, int dst_x, @@ -928,6 +1044,7 @@ _fallback_composite_trapezoids (cairo_operator_t operator, state.image->base.backend->composite_trapezoids (operator, pattern, &state.image->base, + antialias, src_x, src_y, dst_x - state.image_rect.x, dst_y - state.image_rect.y, @@ -945,6 +1062,7 @@ cairo_status_t _cairo_surface_composite_trapezoids (cairo_operator_t operator, cairo_pattern_t *pattern, cairo_surface_t *dst, + cairo_antialias_t antialias, int src_x, int src_y, int dst_x, @@ -965,6 +1083,7 @@ _cairo_surface_composite_trapezoids (cairo_operator_t operator, if (dst->backend->composite_trapezoids) { status = dst->backend->composite_trapezoids (operator, pattern, dst, + antialias, src_x, src_y, dst_x, dst_y, width, height, @@ -974,6 +1093,7 @@ _cairo_surface_composite_trapezoids (cairo_operator_t operator, } return _fallback_composite_trapezoids (operator, pattern, dst, + antialias, src_x, src_y, dst_x, dst_y, width, height, @@ -1076,7 +1196,8 @@ _cairo_surface_reset_clip (cairo_surface_t *surface) status = surface->backend->intersect_clip_path (surface, NULL, CAIRO_FILL_RULE_WINDING, - 0); + 0, + CAIRO_ANTIALIAS_DEFAULT); if (status) return status; } @@ -1122,7 +1243,8 @@ cairo_int_status_t _cairo_surface_intersect_clip_path (cairo_surface_t *surface, cairo_path_fixed_t *path, cairo_fill_rule_t fill_rule, - double tolerance) + double tolerance, + cairo_antialias_t antialias) { if (surface->status) return surface->status; @@ -1135,7 +1257,8 @@ _cairo_surface_intersect_clip_path (cairo_surface_t *surface, return surface->backend->intersect_clip_path (surface, path, fill_rule, - tolerance); + tolerance, + antialias); } static cairo_status_t @@ -1154,21 +1277,20 @@ _cairo_surface_set_clip_path_recursive (cairo_surface_t *surface, return surface->backend->intersect_clip_path (surface, &clip_path->path, clip_path->fill_rule, - clip_path->tolerance); + clip_path->tolerance, + clip_path->antialias); } /** * _cairo_surface_set_clip_path: - * @surface: the #cairo_surface_t to reset the clip on - * @path: the path to intersect against the current clipping path - * @fill_rule: fill rule to use for clipping - * @tolerance: tesselation to use for tesselating clipping path - * @serial: the clip serial number associated with the region + * @surface: the #cairo_surface_t to set the clip on + * @clip_path: the clip path to set + * @serial: the clip serial number associated with the clip path * - * Sets the clipping path to be the intersection of the current - * clipping path of the surface and the given path. + * Sets the given clipping path for the surface and assigns the + * clipping serial to the surface. **/ -cairo_status_t +static cairo_status_t _cairo_surface_set_clip_path (cairo_surface_t *surface, cairo_clip_path_t *clip_path, unsigned int serial) @@ -1186,7 +1308,8 @@ _cairo_surface_set_clip_path (cairo_surface_t *surface, status = surface->backend->intersect_clip_path (surface, NULL, CAIRO_FILL_RULE_WINDING, - 0); + 0, + CAIRO_ANTIALIAS_DEFAULT); if (status) return status; @@ -1199,6 +1322,27 @@ _cairo_surface_set_clip_path (cairo_surface_t *surface, return CAIRO_STATUS_SUCCESS; } +cairo_status_t +_cairo_surface_set_clip (cairo_surface_t *surface, cairo_clip_t *clip) +{ + if (!surface) + return CAIRO_STATUS_NULL_POINTER; + if (clip->serial == _cairo_surface_get_current_clip_serial (surface)) + return CAIRO_STATUS_SUCCESS; + + if (clip->path) + return _cairo_surface_set_clip_path (surface, + clip->path, + clip->serial); + + if (clip->region) + return _cairo_surface_set_clip_region (surface, + clip->region, + clip->serial); + + return _cairo_surface_reset_clip (surface); +} + /** * _cairo_surface_get_extents: * @surface: the #cairo_surface_t to fetch extents for @@ -1260,3 +1404,154 @@ _cairo_surface_show_glyphs (cairo_scaled_font_t *scaled_font, return status; } + +/** + * _cairo_surface_composite_fixup_unbounded: + * @dst: the destination surface + * @src_attr: source surface attributes (from _cairo_pattern_acquire_surface()) + * @src_width: width of source surface + * @src_height: height of source surface + * @mask_attr: mask surface attributes or %NULL if no mask + * @mask_width: width of mask surface + * @mask_height: height of mask surface + * @src_x: @src_x from _cairo_surface_composite() + * @src_y: @src_y from _cairo_surface_composite() + * @mask_x: @mask_x from _cairo_surface_composite() + * @mask_y: @mask_y from _cairo_surface_composite() + * @dst_x: @dst_x from _cairo_surface_composite() + * @dst_y: @dst_y from _cairo_surface_composite() + * @width: @width from _cairo_surface_composite() + * @height: @height_x from _cairo_surface_composite() + * + * Eeek! Too many parameters! This is a helper function to take care of fixing + * up for bugs in libpixman and RENDER where, when asked to composite an + * untransformed surface with an unbounded operator (like CLEAR or SOURCE) + * only the region inside both the source and the mask is affected. + * This function clears the region that should have been drawn but was wasn't. + **/ +void +_cairo_surface_composite_fixup_unbounded (cairo_surface_t *dst, + cairo_surface_attributes_t *src_attr, + int src_width, + int src_height, + cairo_surface_attributes_t *mask_attr, + int mask_width, + int mask_height, + int src_x, + int src_y, + int mask_x, + int mask_y, + int dst_x, + int dst_y, + unsigned int width, + unsigned int height) +{ + cairo_bool_t have_src = TRUE; + cairo_bool_t have_mask = mask_attr != NULL; + cairo_rectangle_t dst_rectangle; + cairo_rectangle_t drawn_rectangle; + cairo_rectangle_t rects[4]; + int num_rects = 0; + + /* The RENDER/libpixman operators are clipped to the bounds of the untransformed, + * non-repeating sources and masks. Other sources and masks can be ignored. + */ + if (!_cairo_matrix_is_integer_translation (&src_attr->matrix, NULL, NULL) || + src_attr->extend != CAIRO_EXTEND_NONE) + have_src = FALSE; + + if (have_mask && + (!_cairo_matrix_is_integer_translation (&mask_attr->matrix, NULL, NULL) || + mask_attr->extend != CAIRO_EXTEND_NONE)) + have_mask = FALSE; + + /* The area that was drawn is the area in the destination rectangle but not within + * the source or the mask. + */ + dst_rectangle.x = dst_x; + dst_rectangle.y = dst_y; + dst_rectangle.width = width; + dst_rectangle.height = height; + + drawn_rectangle = dst_rectangle; + + if (have_src) { + cairo_rectangle_t src_rectangle; + + src_rectangle.x = (dst_x - (src_x + src_attr->x_offset)); + src_rectangle.y = (dst_y - (src_y + src_attr->y_offset)); + src_rectangle.width = src_width; + src_rectangle.height = src_height; + + _cairo_rectangle_intersect (&drawn_rectangle, &src_rectangle); + } + + if (have_mask) { + cairo_rectangle_t mask_rectangle; + + mask_rectangle.x = (dst_x - (mask_x + mask_attr->x_offset)); + mask_rectangle.y = (dst_y - (mask_y + mask_attr->y_offset)); + mask_rectangle.width = mask_width; + mask_rectangle.height = mask_height; + + _cairo_rectangle_intersect (&drawn_rectangle, &mask_rectangle); + } + + /* Now compute the area that is in dst_rectangle but not in drawn_rectangle; + * this is the area we must clear; This computation could be done with + * regions, but the clumsiness of the libpixman API makes this easier. + */ + if (drawn_rectangle.width == 0 || drawn_rectangle.height == 0) + { + rects[num_rects].x = dst_rectangle.x; + rects[num_rects].y = dst_rectangle.y; + rects[num_rects].width = dst_rectangle.width; + rects[num_rects].height = dst_rectangle.height; + + num_rects++; + } + else + { + if (dst_rectangle.y < drawn_rectangle.y) { + rects[num_rects].x = dst_rectangle.x; + rects[num_rects].y = dst_rectangle.y; + rects[num_rects].width = dst_rectangle.width; + rects[num_rects].height = drawn_rectangle.y - dst_rectangle.y; + + num_rects++; + } + + if (dst_rectangle.x < drawn_rectangle.x) { + rects[num_rects].x = dst_rectangle.x; + rects[num_rects].y = drawn_rectangle.y; + rects[num_rects].width = drawn_rectangle.x - dst_rectangle.x; + rects[num_rects].height = drawn_rectangle.height; + + num_rects++; + } + + if (dst_rectangle.x + dst_rectangle.width > drawn_rectangle.x + drawn_rectangle.width) { + rects[num_rects].x = drawn_rectangle.x + drawn_rectangle.width; + rects[num_rects].y = drawn_rectangle.y; + rects[num_rects].width = (dst_rectangle.x + dst_rectangle.width) - (drawn_rectangle.x + drawn_rectangle.width); + rects[num_rects].height = drawn_rectangle.height; + + num_rects++; + } + + if (dst_rectangle.y + dst_rectangle.height > drawn_rectangle.y + drawn_rectangle.height) { + rects[num_rects].x = dst_rectangle.x; + rects[num_rects].y = drawn_rectangle.y + drawn_rectangle.height; + rects[num_rects].width = dst_rectangle.width; + rects[num_rects].height = (dst_rectangle.y + dst_rectangle.height) - (drawn_rectangle.y + drawn_rectangle.height); + + num_rects++; + } + } + + if (num_rects > 0) { + _cairo_surface_fill_rectangles (dst, CAIRO_OPERATOR_SOURCE, CAIRO_COLOR_TRANSPARENT, + rects, num_rects); + } +} + |