Пример #1
0
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;
}
Пример #2
0
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;
}
Пример #3
0
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, &region);

    if (status)
	return status;

    status = CAIRO_STATUS_SUCCESS;

    if (!clip->has_region) {
        status = _cairo_region_copy (&clip->region, &region);
	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,
		                         &region);

	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 (&region);

    if (! _cairo_region_not_empty (&clip->region))
	_cairo_clip_set_all_clipped (clip, target);

    return status;
}
Пример #4
0
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;
}
Пример #5
0
/**
 * _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;
}
Пример #6
0
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;
}
Пример #7
0
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;
}
Пример #8
0
/**
 * 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 (&region->ref_count))
	return;

    assert (CAIRO_REFERENCE_COUNT_HAS_REFERENCE (&region->ref_count));

    if (! _cairo_reference_count_dec_and_test (&region->ref_count))
	return;

    _cairo_region_fini (region);
    free (region);
}
Пример #9
0
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;
}
Пример #10
0
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;
}
Пример #11
0
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;
}
Пример #12
0
/* 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;
}