static cairo_surface_t * _cairo_surface_subsurface_snapshot (void *abstract_surface) { cairo_surface_subsurface_t *surface = abstract_surface; cairo_surface_pattern_t pattern; cairo_surface_t *clone; cairo_status_t status; TRACE ((stderr, "%s: target=%d\n", __FUNCTION__, surface->target->unique_id)); clone = _cairo_surface_create_scratch (surface->target, surface->target->content, surface->extents.width, surface->extents.height, NULL); if (unlikely (clone->status)) return clone; _cairo_pattern_init_for_surface (&pattern, surface->target); cairo_matrix_init_translate (&pattern.base.matrix, surface->extents.x, surface->extents.y); pattern.base.filter = CAIRO_FILTER_NEAREST; status = _cairo_surface_paint (clone, CAIRO_OPERATOR_SOURCE, &pattern.base, NULL); _cairo_pattern_fini (&pattern.base); if (unlikely (status)) { cairo_surface_destroy (clone); clone = _cairo_surface_create_in_error (status); } return clone; }
cairo_surface_t * _cairo_surface_wrapper_create_similar (cairo_surface_wrapper_t *wrapper, cairo_content_t content, int width, int height) { return _cairo_surface_create_scratch (wrapper->target, content, width, height, NULL); }
static cairo_gl_surface_t * tristrip_to_surface (void *_dst, const cairo_rectangle_int_t *extents, cairo_antialias_t antialias, cairo_tristrip_t *strip) { pixman_format_code_t pixman_format; pixman_image_t *pixman_image; cairo_surface_t *image, *mask; cairo_status_t status; pixman_format = antialias != CAIRO_ANTIALIAS_NONE ? PIXMAN_a8 : PIXMAN_a1, pixman_image = pixman_image_create_bits (pixman_format, extents->width, extents->height, NULL, 0); if (unlikely (pixman_image == NULL)) return (cairo_gl_surface_t *)_cairo_surface_create_in_error (_cairo_error (CAIRO_STATUS_NO_MEMORY)); _pixman_image_add_tristrip (pixman_image, extents->x, extents->y, strip); image = _cairo_image_surface_create_for_pixman_image (pixman_image, pixman_format); if (unlikely (image->status)) { pixman_image_unref (pixman_image); return (cairo_gl_surface_t *)image; } mask = _cairo_surface_create_scratch (_dst, CAIRO_CONTENT_COLOR_ALPHA, extents->width, extents->height, NULL); if (unlikely (mask->status)) { cairo_surface_destroy (image); return (cairo_gl_surface_t *)mask; } status = _cairo_gl_surface_draw_image ((cairo_gl_surface_t *)mask, (cairo_image_surface_t *)image, 0, 0, extents->width, extents->height, 0, 0, TRUE); cairo_surface_destroy (image); if (unlikely (status)) { cairo_surface_destroy (mask); return (cairo_gl_surface_t*)_cairo_surface_create_in_error (status); } return (cairo_gl_surface_t*)mask; }
cairo_surface_t * _cairo_clip_get_surface (const cairo_clip_t *clip, cairo_surface_t *target, int *tx, int *ty) { cairo_surface_t *surface; cairo_status_t status; cairo_clip_t *copy, *region; cairo_clip_path_t *copy_path, *clip_path; if (clip->num_boxes) { cairo_path_fixed_t path; int i; surface = _cairo_surface_create_scratch (target, CAIRO_CONTENT_ALPHA, clip->extents.width, clip->extents.height, CAIRO_COLOR_TRANSPARENT); if (unlikely (surface->status)) return surface; _cairo_path_fixed_init (&path); status = CAIRO_STATUS_SUCCESS; for (i = 0; status == CAIRO_STATUS_SUCCESS && i < clip->num_boxes; i++) { status = _cairo_path_fixed_add_box (&path, &clip->boxes[i], -_cairo_fixed_from_int (clip->extents.x), -_cairo_fixed_from_int (clip->extents.y)); } if (status == CAIRO_STATUS_SUCCESS) status = _cairo_surface_fill (surface, CAIRO_OPERATOR_ADD, &_cairo_pattern_white.base, &path, CAIRO_FILL_RULE_WINDING, 1., CAIRO_ANTIALIAS_DEFAULT, NULL); _cairo_path_fixed_fini (&path); if (unlikely (status)) { cairo_surface_destroy (surface); return _cairo_surface_create_in_error (status); } } else { surface = _cairo_surface_create_scratch (target, CAIRO_CONTENT_ALPHA, clip->extents.width, clip->extents.height, CAIRO_COLOR_WHITE); if (unlikely (surface->status)) return surface; } copy = _cairo_clip_copy_with_translation (clip, -clip->extents.x, -clip->extents.y); copy_path = copy->path; copy->path = NULL; region = copy; if (! _cairo_clip_is_region (copy)) region = _cairo_clip_copy_region (copy); status = CAIRO_STATUS_SUCCESS; clip_path = copy_path; while (status == CAIRO_STATUS_SUCCESS && clip_path) { status = _cairo_surface_fill (surface, CAIRO_OPERATOR_IN, &_cairo_pattern_white.base, &clip_path->path, clip_path->fill_rule, clip_path->tolerance, clip_path->antialias, region); clip_path = clip_path->prev; } copy->path = copy_path; _cairo_clip_destroy (copy); if (region != copy) _cairo_clip_destroy (region); if (unlikely (status)) { cairo_surface_destroy (surface); return _cairo_surface_create_in_error (status); } *tx = clip->extents.x; *ty = clip->extents.y; return surface; }
static cairo_int_status_t _cairo_shape_mask_compositor_stroke (const cairo_compositor_t *_compositor, cairo_composite_rectangles_t *extents, const cairo_path_fixed_t *path, const cairo_stroke_style_t *style, const cairo_matrix_t *ctm, const cairo_matrix_t *ctm_inverse, double tolerance, cairo_antialias_t antialias) { cairo_surface_t *mask; cairo_surface_pattern_t pattern; cairo_int_status_t status; cairo_clip_t *clip; if (! extents->is_bounded) return CAIRO_INT_STATUS_UNSUPPORTED; TRACE ((stderr, "%s\n", __FUNCTION__)); mask = _cairo_surface_create_scratch (extents->surface, CAIRO_CONTENT_ALPHA, extents->bounded.width, extents->bounded.height, NULL); if (unlikely (mask->status)) return mask->status; clip = extents->clip; if (! _cairo_clip_is_region (clip)) clip = _cairo_clip_copy_region (clip); if (! mask->is_clear) { status = _cairo_surface_offset_paint (mask, extents->bounded.x, extents->bounded.y, CAIRO_OPERATOR_CLEAR, &_cairo_pattern_clear.base, clip); if (unlikely (status)) goto error; } status = _cairo_surface_offset_stroke (mask, extents->bounded.x, extents->bounded.y, CAIRO_OPERATOR_ADD, &_cairo_pattern_white.base, path, style, ctm, ctm_inverse, tolerance, antialias, clip); if (unlikely (status)) goto error; if (clip != extents->clip) { status = _cairo_clip_combine_with_surface (extents->clip, mask, extents->bounded.x, extents->bounded.y); if (unlikely (status)) goto error; } _cairo_pattern_init_for_surface (&pattern, mask); cairo_matrix_init_translate (&pattern.base.matrix, -extents->bounded.x, -extents->bounded.y); pattern.base.filter = CAIRO_FILTER_NEAREST; pattern.base.extend = CAIRO_EXTEND_NONE; if (extents->op == CAIRO_OPERATOR_SOURCE) { status = _cairo_surface_mask (extents->surface, CAIRO_OPERATOR_DEST_OUT, &_cairo_pattern_white.base, &pattern.base, clip); if ((status == CAIRO_INT_STATUS_SUCCESS)) { status = _cairo_surface_mask (extents->surface, CAIRO_OPERATOR_ADD, &extents->source_pattern.base, &pattern.base, clip); } } else { status = _cairo_surface_mask (extents->surface, extents->op, &extents->source_pattern.base, &pattern.base, clip); } _cairo_pattern_fini (&pattern.base); error: cairo_surface_destroy (mask); if (clip != extents->clip) _cairo_clip_destroy (clip); return status; }
static cairo_status_t _cairo_default_context_push_group (void *abstract_cr, cairo_content_t content) { cairo_default_context_t *cr = abstract_cr; cairo_surface_t *group_surface; cairo_clip_t *clip; cairo_status_t status; clip = _cairo_gstate_get_clip (cr->gstate); if (_cairo_clip_is_all_clipped (clip)) { group_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 0, 0); status = group_surface->status; if (unlikely (status)) goto bail; } else { cairo_surface_t *parent_surface; cairo_rectangle_int_t extents; cairo_bool_t bounded, is_empty; parent_surface = _cairo_gstate_get_target (cr->gstate); if (unlikely (parent_surface->status)) return parent_surface->status; if (unlikely (parent_surface->finished)) return _cairo_error (CAIRO_STATUS_SURFACE_FINISHED); /* Get the extents that we'll use in creating our new group surface */ bounded = _cairo_surface_get_extents (parent_surface, &extents); if (clip) /* XXX: This assignment just fixes a compiler warning? */ is_empty = _cairo_rectangle_intersect (&extents, _cairo_clip_get_extents (clip)); if (!bounded) { /* XXX: Generic solution? */ group_surface = cairo_recording_surface_create (content, NULL); extents.x = extents.y = 0; } else { group_surface = _cairo_surface_create_scratch (parent_surface, content, extents.width, extents.height, CAIRO_COLOR_TRANSPARENT); } status = group_surface->status; if (unlikely (status)) goto bail; /* Set device offsets on the new surface so that logically it appears at * the same location on the parent surface -- when we pop_group this, * the source pattern will get fixed up for the appropriate target surface * device offsets, so we want to set our own surface offsets from /that/, * and not from the device origin. */ cairo_surface_set_device_offset (group_surface, parent_surface->device_transform.x0 - extents.x, parent_surface->device_transform.y0 - extents.y); cairo_surface_set_device_scale (group_surface, parent_surface->device_transform.xx, parent_surface->device_transform.yy); /* If we have a current path, we need to adjust it to compensate for * the device offset just applied. */ _cairo_path_fixed_translate (cr->path, _cairo_fixed_from_int (-extents.x), _cairo_fixed_from_int (-extents.y)); } /* create a new gstate for the redirect */ status = _cairo_gstate_save (&cr->gstate, &cr->gstate_freelist); if (unlikely (status)) goto bail; status = _cairo_gstate_redirect_target (cr->gstate, group_surface); bail: cairo_surface_destroy (group_surface); return status; }
static cairo_surface_t * get_clip_surface (const cairo_spans_compositor_t *compositor, cairo_surface_t *dst, const cairo_clip_t *clip, const cairo_rectangle_int_t *extents) { cairo_composite_rectangles_t composite; cairo_surface_t *surface; cairo_box_t box; cairo_polygon_t polygon; const cairo_clip_path_t *clip_path; cairo_antialias_t antialias; cairo_fill_rule_t fill_rule; cairo_int_status_t status; assert (clip->path); surface = _cairo_surface_create_scratch (dst, CAIRO_CONTENT_ALPHA, extents->width, extents->height, CAIRO_COLOR_TRANSPARENT); #ifdef WKC_CAIRO_CUSTOMIZE if (unlikely (surface->status)) return surface; #endif _cairo_box_from_rectangle (&box, extents); _cairo_polygon_init (&polygon, &box, 1); clip_path = clip->path; status = _cairo_path_fixed_fill_to_polygon (&clip_path->path, clip_path->tolerance, &polygon); if (unlikely (status)) goto cleanup_polygon; polygon.num_limits = 0; antialias = clip_path->antialias; fill_rule = clip_path->fill_rule; if (clip->boxes) { cairo_polygon_t intersect; cairo_boxes_t tmp; _cairo_boxes_init_for_array (&tmp, clip->boxes, clip->num_boxes); status= _cairo_polygon_init_boxes (&intersect, &tmp); if (unlikely (status)) goto cleanup_polygon; status = _cairo_polygon_intersect (&polygon, fill_rule, &intersect, CAIRO_FILL_RULE_WINDING); _cairo_polygon_fini (&intersect); if (unlikely (status)) goto cleanup_polygon; fill_rule = CAIRO_FILL_RULE_WINDING; } polygon.limits = NULL; polygon.num_limits = 0; clip_path = clip_path->prev; while (clip_path) { if (clip_path->antialias == antialias) { cairo_polygon_t next; _cairo_polygon_init (&next, NULL, 0); status = _cairo_path_fixed_fill_to_polygon (&clip_path->path, clip_path->tolerance, &next); if (likely (status == CAIRO_INT_STATUS_SUCCESS)) status = _cairo_polygon_intersect (&polygon, fill_rule, &next, clip_path->fill_rule); _cairo_polygon_fini (&next); if (unlikely (status)) goto cleanup_polygon; fill_rule = CAIRO_FILL_RULE_WINDING; } clip_path = clip_path->prev; } _cairo_polygon_translate (&polygon, -extents->x, -extents->y); status = _cairo_composite_rectangles_init_for_polygon (&composite, surface, CAIRO_OPERATOR_ADD, &_cairo_pattern_white.base, &polygon, NULL); if (unlikely (status)) goto cleanup_polygon; status = composite_polygon (compositor, &composite, &polygon, fill_rule, antialias); _cairo_composite_rectangles_fini (&composite); _cairo_polygon_fini (&polygon); if (unlikely (status)) goto error; _cairo_polygon_init (&polygon, &box, 1); clip_path = clip->path; antialias = clip_path->antialias == CAIRO_ANTIALIAS_DEFAULT ? CAIRO_ANTIALIAS_NONE : CAIRO_ANTIALIAS_DEFAULT; clip_path = clip_path->prev; while (clip_path) { if (clip_path->antialias == antialias) { if (polygon.num_edges == 0) { status = _cairo_path_fixed_fill_to_polygon (&clip_path->path, clip_path->tolerance, &polygon); fill_rule = clip_path->fill_rule; polygon.limits = NULL; polygon.num_limits = 0; } else { cairo_polygon_t next; _cairo_polygon_init (&next, NULL, 0); status = _cairo_path_fixed_fill_to_polygon (&clip_path->path, clip_path->tolerance, &next); if (likely (status == CAIRO_INT_STATUS_SUCCESS)) status = _cairo_polygon_intersect (&polygon, fill_rule, &next, clip_path->fill_rule); _cairo_polygon_fini (&next); fill_rule = CAIRO_FILL_RULE_WINDING; } if (unlikely (status)) goto error; } clip_path = clip_path->prev; } if (polygon.num_edges) { _cairo_polygon_translate (&polygon, -extents->x, -extents->y); status = _cairo_composite_rectangles_init_for_polygon (&composite, surface, CAIRO_OPERATOR_IN, &_cairo_pattern_white.base, &polygon, NULL); if (unlikely (status)) goto cleanup_polygon; status = composite_polygon (compositor, &composite, &polygon, fill_rule, antialias); _cairo_composite_rectangles_fini (&composite); _cairo_polygon_fini (&polygon); if (unlikely (status)) goto error; } return surface; cleanup_polygon: _cairo_polygon_fini (&polygon); error: cairo_surface_destroy (surface); return _cairo_int_surface_create_in_error (status); }
static cairo_int_status_t traps_to_operand (void *_dst, const cairo_rectangle_int_t *extents, cairo_antialias_t antialias, cairo_traps_t *traps, cairo_gl_operand_t *operand, int dst_x, int dst_y) { pixman_format_code_t pixman_format; pixman_image_t *pixman_image; cairo_surface_t *image, *mask; cairo_surface_pattern_t pattern; cairo_status_t status; pixman_format = antialias != CAIRO_ANTIALIAS_NONE ? PIXMAN_a8 : PIXMAN_a1; pixman_image = pixman_image_create_bits (pixman_format, extents->width, extents->height, NULL, 0); if (unlikely (pixman_image == NULL)) return _cairo_error (CAIRO_STATUS_NO_MEMORY); _pixman_image_add_traps (pixman_image, extents->x, extents->y, traps); image = _cairo_image_surface_create_for_pixman_image (pixman_image, pixman_format); if (unlikely (image->status)) { pixman_image_unref (pixman_image); return image->status; } /* GLES2 only supports RGB/RGBA when uploading */ if (_cairo_gl_get_flavor () == CAIRO_GL_FLAVOR_ES) { cairo_surface_pattern_t pattern; cairo_surface_t *rgba_image; /* XXX perform this fixup inside _cairo_gl_draw_image() */ rgba_image = _cairo_image_surface_create_with_pixman_format (NULL, _cairo_is_little_endian () ? PIXMAN_a8b8g8r8 : PIXMAN_r8g8b8a8, extents->width, extents->height, 0); if (unlikely (rgba_image->status)) return rgba_image->status; _cairo_pattern_init_for_surface (&pattern, image); status = _cairo_surface_paint (rgba_image, CAIRO_OPERATOR_SOURCE, &pattern.base, NULL); _cairo_pattern_fini (&pattern.base); cairo_surface_destroy (image); image = rgba_image; if (unlikely (status)) { cairo_surface_destroy (image); return status; } } mask = _cairo_surface_create_scratch (_dst, CAIRO_CONTENT_COLOR_ALPHA, extents->width, extents->height, NULL); if (unlikely (mask->status)) { cairo_surface_destroy (image); return mask->status; } status = _cairo_gl_surface_draw_image ((cairo_gl_surface_t *)mask, (cairo_image_surface_t *)image, 0, 0, extents->width, extents->height, 0, 0, TRUE); cairo_surface_destroy (image); if (unlikely (status)) goto error; _cairo_pattern_init_for_surface (&pattern, mask); cairo_matrix_init_translate (&pattern.base.matrix, -extents->x+dst_x, -extents->y+dst_y); pattern.base.filter = CAIRO_FILTER_NEAREST; pattern.base.extend = CAIRO_EXTEND_NONE; status = _cairo_gl_operand_init (operand, &pattern.base, _dst, &_cairo_unbounded_rectangle, &_cairo_unbounded_rectangle, FALSE); _cairo_pattern_fini (&pattern.base); if (unlikely (status)) goto error; operand->texture.owns_surface = (cairo_gl_surface_t *)mask; return CAIRO_STATUS_SUCCESS; error: cairo_surface_destroy (mask); return status; }