static cairo_status_t _cairo_analysis_surface_finish (void *abstract_surface) { cairo_analysis_surface_t *surface = (cairo_analysis_surface_t *) abstract_surface; _cairo_region_fini (&surface->supported_region); _cairo_region_fini (&surface->fallback_region); cairo_surface_destroy (surface->target); return CAIRO_STATUS_SUCCESS; }
cairo_status_t _cairo_clip_init_copy (cairo_clip_t *clip, cairo_clip_t *other) { clip->mode = other->mode; clip->all_clipped = other->all_clipped; clip->surface = cairo_surface_reference (other->surface); clip->surface_rect = other->surface_rect; clip->serial = other->serial; _cairo_region_init (&clip->region); if (other->has_region) { cairo_status_t status; status = _cairo_region_copy (&clip->region, &other->region); if (status) { _cairo_region_fini (&clip->region); cairo_surface_destroy (clip->surface); return status; } clip->has_region = TRUE; } else { clip->has_region = FALSE; } clip->path = _cairo_clip_path_reference (other->path); return CAIRO_STATUS_SUCCESS; }
static cairo_int_status_t _cairo_clip_intersect_region (cairo_clip_t *clip, cairo_traps_t *traps, cairo_surface_t *target) { cairo_region_t region; cairo_int_status_t status; if (clip->all_clipped) return CAIRO_STATUS_SUCCESS; if (clip->mode != CAIRO_CLIP_MODE_REGION) return CAIRO_INT_STATUS_UNSUPPORTED; status = _cairo_traps_extract_region (traps, ®ion); if (status) return status; status = CAIRO_STATUS_SUCCESS; if (!clip->has_region) { status = _cairo_region_copy (&clip->region, ®ion); if (status == CAIRO_STATUS_SUCCESS) clip->has_region = TRUE; } else { cairo_region_t intersection; _cairo_region_init (&intersection); status = _cairo_region_intersect (&intersection, &clip->region, ®ion); if (status == CAIRO_STATUS_SUCCESS) status = _cairo_region_copy (&clip->region, &intersection); _cairo_region_fini (&intersection); } clip->serial = _cairo_surface_allocate_clip_serial (target); _cairo_region_fini (®ion); if (! _cairo_region_not_empty (&clip->region)) _cairo_clip_set_all_clipped (clip, target); return status; }
cairo_status_t _cairo_clip_intersect_to_region (cairo_clip_t *clip, cairo_region_t *region) { cairo_status_t status; if (!clip) return CAIRO_STATUS_SUCCESS; if (clip->all_clipped) { cairo_region_t clip_rect; _cairo_region_init_rect (&clip_rect, &clip->surface_rect); status = _cairo_region_intersect (region, &clip_rect, region); _cairo_region_fini (&clip_rect); return status; } if (clip->path) { /* Intersect clip path into region. */ } if (clip->has_region) { status = _cairo_region_intersect (region, &clip->region, region); if (status) return status; } if (clip->surface) { cairo_region_t clip_rect; _cairo_region_init_rect (&clip_rect, &clip->surface_rect); status = _cairo_region_intersect (region, &clip_rect, region); _cairo_region_fini (&clip_rect); if (status) return status; } return CAIRO_STATUS_SUCCESS; }
/** * _cairo_traps_extract_region: * @traps: a #cairo_traps_t * @region: a #cairo_region_t * * Determines if a set of trapezoids are exactly representable as a * cairo region. If so, the passed-in region is initialized to * the area representing the given traps. It should be finalized * with _cairo_region_fini(). If not, %CAIRO_INT_STATUS_UNSUPPORTED * is returned. * * Return value: %CAIRO_STATUS_SUCCESS, %CAIRO_INT_STATUS_UNSUPPORTED * or %CAIRO_STATUS_NO_MEMORY **/ cairo_int_status_t _cairo_traps_extract_region (cairo_traps_t *traps, cairo_region_t *region) { cairo_box_int_t stack_boxes[CAIRO_STACK_ARRAY_LENGTH (cairo_box_int_t)]; cairo_box_int_t *boxes = stack_boxes; int i, box_count; cairo_int_status_t status; for (i = 0; i < traps->num_traps; i++) if (!(traps->traps[i].left.p1.x == traps->traps[i].left.p2.x && traps->traps[i].right.p1.x == traps->traps[i].right.p2.x && _cairo_fixed_is_integer(traps->traps[i].top) && _cairo_fixed_is_integer(traps->traps[i].bottom) && _cairo_fixed_is_integer(traps->traps[i].left.p1.x) && _cairo_fixed_is_integer(traps->traps[i].right.p1.x))) { return CAIRO_INT_STATUS_UNSUPPORTED; } if (traps->num_traps > ARRAY_LENGTH(stack_boxes)) { boxes = _cairo_malloc_ab (traps->num_traps, sizeof(cairo_box_int_t)); if (boxes == NULL) return _cairo_error (CAIRO_STATUS_NO_MEMORY); } box_count = 0; for (i = 0; i < traps->num_traps; i++) { int x1 = _cairo_fixed_integer_part(traps->traps[i].left.p1.x); int y1 = _cairo_fixed_integer_part(traps->traps[i].top); int x2 = _cairo_fixed_integer_part(traps->traps[i].right.p1.x); int y2 = _cairo_fixed_integer_part(traps->traps[i].bottom); /* XXX: Sometimes we get degenerate trapezoids from the tesellator; * skip these. */ if (x1 == x2 || y1 == y2) continue; boxes[box_count].p1.x = x1; boxes[box_count].p1.y = y1; boxes[box_count].p2.x = x2; boxes[box_count].p2.y = y2; box_count++; } status = _cairo_region_init_boxes (region, boxes, box_count); if (boxes != stack_boxes) free (boxes); if (status) _cairo_region_fini (region); return status; }
cairo_status_t _cairo_clip_init_deep_copy (cairo_clip_t *clip, cairo_clip_t *other, cairo_surface_t *target) { cairo_status_t status; _cairo_clip_init (clip, target); if (other->mode != clip->mode) { /* We should reapply the original clip path in this case, and let * whatever the right handling is happen */ } else { if (other->has_region) { status = _cairo_region_copy (&clip->region, &other->region); if (unlikely (status)) goto BAIL; clip->has_region = TRUE; } if (other->surface) { int dx, dy; status = _cairo_surface_clone_similar (target, other->surface, 0, 0, other->surface_rect.width, other->surface_rect.height, &dx, &dy, &clip->surface); if (unlikely (status)) goto BAIL; clip->surface_rect = other->surface_rect; /* src offset was 0, so we expect an exact replica of the surface */ assert (dx == 0); assert (dy == 0); } if (other->path) { status = _cairo_clip_path_reapply_clip_path (clip, other->path); if (_cairo_status_is_error (status)) goto BAIL; } } return CAIRO_STATUS_SUCCESS; BAIL: if (clip->has_region) _cairo_region_fini (&clip->region); if (clip->surface) cairo_surface_destroy (clip->surface); return status; }
cairo_status_t _cairo_clip_init_deep_copy (cairo_clip_t *clip, cairo_clip_t *other, cairo_surface_t *target) { cairo_status_t status; _cairo_clip_init (clip, target); if (other->mode != clip->mode) { /* We should reapply the original clip path in this case, and let * whatever the right handling is happen */ } else { if (other->has_region) { status = _cairo_region_copy (&clip->region, &other->region); if (status) goto BAIL; clip->has_region = TRUE; } if (other->surface) { status = _cairo_surface_clone_similar (target, other->surface, other->surface_rect.x, other->surface_rect.y, other->surface_rect.width, other->surface_rect.height, &clip->surface); if (status) goto BAIL; clip->surface_rect = other->surface_rect; } if (other->path) { status = _cairo_clip_path_reapply_clip_path (clip, other->path); if (status && status != CAIRO_INT_STATUS_UNSUPPORTED) goto BAIL; } } return CAIRO_STATUS_SUCCESS; BAIL: if (clip->has_region) _cairo_region_fini (&clip->region); if (clip->surface) cairo_surface_destroy (clip->surface); return status; }
/** * cairo_region_destroy: * @region: a #cairo_region_t * * Destroys a #cairo_region_t object created with * cairo_region_create(), cairo_region_copy(), or * or cairo_region_create_rectangle(). * * Since: 1.10 **/ void cairo_region_destroy (cairo_region_t *region) { if (region == NULL || CAIRO_REFERENCE_COUNT_IS_INVALID (®ion->ref_count)) return; assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (®ion->ref_count)); if (! _cairo_reference_count_dec_and_test (®ion->ref_count)) return; _cairo_region_fini (region); free (region); }
cairo_status_t _cairo_clip_intersect_to_rectangle (cairo_clip_t *clip, cairo_rectangle_int_t *rectangle) { if (!clip) return CAIRO_STATUS_SUCCESS; if (clip->all_clipped) { *rectangle = clip->surface_rect; return CAIRO_STATUS_SUCCESS; } if (clip->path) { cairo_status_t status; status = _cairo_clip_path_intersect_to_rectangle (clip->path, rectangle); if (status) return status; } if (clip->has_region) { cairo_status_t status = CAIRO_STATUS_SUCCESS; cairo_region_t intersection; _cairo_region_init_rect (&intersection, rectangle); status = _cairo_region_intersect (&intersection, &clip->region, &intersection); if (!status) _cairo_region_get_extents (&intersection, rectangle); _cairo_region_fini (&intersection); if (status) return status; } if (clip->surface) _cairo_rectangle_intersect (rectangle, &clip->surface_rect); return CAIRO_STATUS_SUCCESS; }
void _cairo_clip_reset (cairo_clip_t *clip) { clip->all_clipped = FALSE; /* destroy any existing clip-region artifacts */ cairo_surface_destroy (clip->surface); clip->surface = NULL; clip->serial = 0; if (clip->has_region) { /* _cairo_region_fini just releases the resources used but * doesn't bother with leaving the region in a valid state. * So _cairo_region_init has to be called afterwards. */ _cairo_region_fini (&clip->region); _cairo_region_init (&clip->region); clip->has_region = FALSE; } _cairo_clip_path_destroy (clip->path); clip->path = NULL; }
static cairo_status_t _combine_region (cairo_surface_t *surface, const cairo_region_t *region, const cairo_rectangle_int_t *extents) { cairo_region_t clear_region; cairo_status_t status; _cairo_region_init_rectangle (&clear_region, extents); status = cairo_region_subtract (&clear_region, region); if (unlikely (status)) return status; if (! cairo_region_is_empty (&clear_region)) { cairo_region_translate (&clear_region, -extents->x, -extents->y); status = _cairo_surface_fill_region (surface, CAIRO_OPERATOR_CLEAR, CAIRO_COLOR_TRANSPARENT, &clear_region); } _cairo_region_fini (&clear_region); return status; }
/* Warning: This call modifies the coordinates of traps */ static cairo_status_t _clip_and_composite_trapezoids (cairo_pattern_t *src, cairo_operator_t op, cairo_surface_t *dst, cairo_traps_t *traps, cairo_clip_t *clip, cairo_antialias_t antialias) { cairo_status_t status; cairo_region_t trap_region; cairo_region_t clear_region; cairo_bool_t has_trap_region = FALSE; cairo_bool_t has_clear_region = FALSE; cairo_rectangle_int_t extents; cairo_composite_traps_info_t traps_info; if (traps->num_traps == 0) return CAIRO_STATUS_SUCCESS; status = _cairo_surface_get_extents (dst, &extents); if (status) return status; status = _cairo_traps_extract_region (traps, &trap_region); if (CAIRO_INT_STATUS_UNSUPPORTED == status) { has_trap_region = FALSE; } else if (status) { return status; } else { has_trap_region = TRUE; } if (_cairo_operator_bounded_by_mask (op)) { cairo_rectangle_int_t trap_extents; if (has_trap_region) { status = _cairo_clip_intersect_to_region (clip, &trap_region); if (status) goto out; _cairo_region_get_extents (&trap_region, &trap_extents); } else { cairo_box_t trap_box; _cairo_traps_extents (traps, &trap_box); _cairo_box_round_to_rectangle (&trap_box, &trap_extents); } _cairo_rectangle_intersect (&extents, &trap_extents); status = _cairo_clip_intersect_to_rectangle (clip, &extents); if (status) goto out; } else { cairo_surface_t *clip_surface = clip ? clip->surface : NULL; if (has_trap_region && !clip_surface) { /* If we optimize drawing with an unbounded operator to * _cairo_surface_fill_rectangles() or to drawing with a * clip region, then we have an additional region to clear. */ _cairo_region_init_rect (&clear_region, &extents); has_clear_region = TRUE; status = _cairo_clip_intersect_to_region (clip, &clear_region); if (status) goto out; _cairo_region_get_extents (&clear_region, &extents); status = _cairo_region_subtract (&clear_region, &clear_region, &trap_region); if (status) goto out; if (!_cairo_region_not_empty (&clear_region)) { _cairo_region_fini (&clear_region); has_clear_region = FALSE; } } else { status = _cairo_clip_intersect_to_rectangle (clip, &extents); } } if (status) goto out; if (has_trap_region) { cairo_surface_t *clip_surface = clip ? clip->surface : NULL; if ((src->type == CAIRO_PATTERN_TYPE_SOLID || op == CAIRO_OPERATOR_CLEAR) && !clip_surface) { const cairo_color_t *color; if (op == CAIRO_OPERATOR_CLEAR) { color = CAIRO_COLOR_TRANSPARENT; } else { color = &((cairo_solid_pattern_t *)src)->color; } /* Solid rectangles special case */ status = _cairo_surface_fill_region (dst, op, color, &trap_region); if (!status && has_clear_region) status = _cairo_surface_fill_region (dst, CAIRO_OPERATOR_CLEAR, CAIRO_COLOR_TRANSPARENT, &clear_region); goto out; } if ((_cairo_operator_bounded_by_mask (op) && op != CAIRO_OPERATOR_SOURCE) || !clip_surface) { /* For a simple rectangle, we can just use composite(), for more * rectangles, we have to set a clip region. The cost of rasterizing * trapezoids is pretty high for most backends currently, so it's * worthwhile even if a region is needed. * * If we have a clip surface, we set it as the mask; this only works * for bounded operators other than SOURCE; for unbounded operators, * clip and mask cannot be interchanged. For SOURCE, the operator * as implemented by the backends is different in it's handling * of the mask then what we want. * * CAIRO_INT_STATUS_UNSUPPORTED will be returned if the region has * more than rectangle and the destination doesn't support clip * regions. In that case, we fall through. */ status = _composite_trap_region (clip, src, op, dst, &trap_region, &extents); if (status != CAIRO_INT_STATUS_UNSUPPORTED) { if (!status && has_clear_region) status = _cairo_surface_fill_region (dst, CAIRO_OPERATOR_CLEAR, CAIRO_COLOR_TRANSPARENT, &clear_region); goto out; } } } traps_info.traps = traps; traps_info.antialias = antialias; status = _clip_and_composite (clip, op, src, _composite_traps_draw_func, &traps_info, dst, &extents); out: if (has_trap_region) _cairo_region_fini (&trap_region); if (has_clear_region) _cairo_region_fini (&clear_region); return status; }