예제 #1
0
cairo_status_t
_cairo_pen_init_copy (cairo_pen_t *pen, cairo_pen_t *other)
{
    *pen = *other;

    if (pen->num_vertices) {
	pen->vertices = _cairo_malloc_ab (pen->num_vertices, sizeof (cairo_pen_vertex_t));
	if (pen->vertices == NULL) {
	    return CAIRO_STATUS_NO_MEMORY;
	}
	memcpy (pen->vertices, other->vertices, pen->num_vertices * sizeof (cairo_pen_vertex_t));
    }

    return CAIRO_STATUS_SUCCESS;
}
예제 #2
0
static cairo_int_status_t
_cairo_image_surface_fill_rectangles (void		      *abstract_surface,
				      cairo_operator_t	       op,
				      const cairo_color_t     *color,
				      cairo_rectangle_int_t   *rects,
				      int		       num_rects)
{
    cairo_image_surface_t *surface = abstract_surface;

    pixman_color_t pixman_color;
    pixman_rectangle16_t stack_rects[CAIRO_STACK_ARRAY_LENGTH (pixman_rectangle16_t)];
    pixman_rectangle16_t *pixman_rects = stack_rects;
    int i;

    cairo_int_status_t status = CAIRO_STATUS_SUCCESS;

    pixman_color.red   = color->red_short;
    pixman_color.green = color->green_short;
    pixman_color.blue  = color->blue_short;
    pixman_color.alpha = color->alpha_short;

    if (num_rects > ARRAY_LENGTH (stack_rects)) {
	pixman_rects = _cairo_malloc_ab (num_rects, sizeof (pixman_rectangle16_t));
	if (pixman_rects == NULL)
	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    }

    for (i = 0; i < num_rects; i++) {
	pixman_rects[i].x = rects[i].x;
	pixman_rects[i].y = rects[i].y;
	pixman_rects[i].width = rects[i].width;
	pixman_rects[i].height = rects[i].height;
    }

    /* XXX: pixman_fill_rectangles() should be implemented */
    if (! pixman_image_fill_rectangles (_pixman_operator (op),
				       surface->pixman_image,
				       &pixman_color,
				       num_rects,
				       pixman_rects)) {
	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
    }

    if (pixman_rects != stack_rects)
	free (pixman_rects);

    return status;
}
예제 #3
0
static cairo_path_t *
_cairo_path_create_internal (cairo_path_fixed_t *path_fixed,
			     cairo_gstate_t     *gstate,
			     cairo_bool_t	 flatten)
{
    cairo_path_t *path;

    //+EAWebKitChange
    //11/10/2011
    path = cairo_malloc (sizeof (cairo_path_t));
    //-EAWebKitChange
    if (path == NULL) {
	_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
	return (cairo_path_t*) &_cairo_path_nil;
    }

    path->num_data = _cairo_path_count (path, path_fixed,
					_cairo_gstate_get_tolerance (gstate),
					flatten);
    if (path->num_data < 0) {
        //+EAWebKitChange
        //11/10/2011
        cairo_free (path);
        //-EAWebKitChange
	return (cairo_path_t*) &_cairo_path_nil;
    }

    if (path->num_data) {
	path->data = _cairo_malloc_ab (path->num_data,
	       	                       sizeof (cairo_path_data_t));
	if (path->data == NULL) {
        //+EAWebKitChange
        //11/10/2011
        cairo_free (path);
        //-EAWebKitChange
	    _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
	    return (cairo_path_t*) &_cairo_path_nil;
	}

	path->status = _cairo_path_populate (path, path_fixed,
					     gstate, flatten);
    } else {
	path->data = NULL;
	path->status = CAIRO_STATUS_SUCCESS;
    }

    return path;
}
예제 #4
0
파일: cairo-polygon.c 프로젝트: mgya/xCairo
cairo_status_t
_cairo_polygon_init_boxes (cairo_polygon_t *polygon,
			   const cairo_boxes_t *boxes)
{
    const struct _cairo_boxes_chunk *chunk;
    int i;

    VG (VALGRIND_MAKE_MEM_UNDEFINED (polygon, sizeof (cairo_polygon_t)));

    polygon->status = CAIRO_STATUS_SUCCESS;

    polygon->num_edges = 0;

    polygon->edges = polygon->edges_embedded;
    polygon->edges_size = ARRAY_LENGTH (polygon->edges_embedded);
    if (boxes->num_boxes > ARRAY_LENGTH (polygon->edges_embedded)/2) {
	polygon->edges_size = 2 * boxes->num_boxes;
	polygon->edges = _cairo_malloc_ab (polygon->edges_size,
					   2*sizeof(cairo_edge_t));
	if (unlikely (polygon->edges == XNULL))
	    return polygon->status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
    }

    polygon->extents.p1.x = polygon->extents.p1.y = INT32_MAX;
    polygon->extents.p2.x = polygon->extents.p2.y = INT32_MIN;

    polygon->limits = XNULL;
    polygon->num_limits = 0;

    for (chunk = &boxes->chunks; chunk != XNULL; chunk = chunk->next) {
	for (i = 0; i < chunk->count; i++) {
	    cairo_point_t p1, p2;

	    p1 = chunk->base[i].p1;
	    p2.x = p1.x;
	    p2.y = chunk->base[i].p2.y;
	    _cairo_polygon_add_edge (polygon, &p1, &p2, 1);

	    p1 = chunk->base[i].p2;
	    p2.x = p1.x;
	    p2.y = chunk->base[i].p1.y;
	    _cairo_polygon_add_edge (polygon, &p1, &p2, 1);
	}
    }

    return polygon->status;
}
예제 #5
0
파일: cairo-pen.c 프로젝트: 3oyka/cairo2
cairo_status_t
_cairo_pen_init (cairo_pen_t	*pen,
		 double		 radius,
		 double		 tolerance,
		 cairo_matrix_t	*ctm)
{
    int i;
    int reflect;

    pen->radius = radius;
    pen->tolerance = tolerance;

    reflect = _cairo_matrix_compute_determinant (ctm) < 0.;

    pen->num_vertices = _cairo_pen_vertices_needed (tolerance,
						    radius,
						    ctm);

    if (pen->num_vertices > ARRAY_LENGTH (pen->vertices_embedded)) {
	pen->vertices = _cairo_malloc_ab (pen->num_vertices,
					  sizeof (cairo_pen_vertex_t));
	if (pen->vertices == NULL)
	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    } else {
	pen->vertices = pen->vertices_embedded;
    }

    /*
     * Compute pen coordinates.  To generate the right ellipse, compute points around
     * a circle in user space and transform them to device space.  To get a consistent
     * orientation in device space, flip the pen if the transformation matrix
     * is reflecting
     */
    for (i=0; i < pen->num_vertices; i++) {
	double theta = 2 * M_PI * i / (double) pen->num_vertices;
	double dx = radius * cos (reflect ? -theta : theta);
	double dy = radius * sin (reflect ? -theta : theta);
	cairo_pen_vertex_t *v = &pen->vertices[i];
	cairo_matrix_transform_distance (ctm, &dx, &dy);
	v->point.x = _cairo_fixed_from_double (dx);
	v->point.y = _cairo_fixed_from_double (dy);
    }

    _cairo_pen_compute_slopes (pen);

    return CAIRO_STATUS_SUCCESS;
}
예제 #6
0
파일: cairo-pen.c 프로젝트: 3oyka/cairo2
cairo_status_t
_cairo_pen_add_points (cairo_pen_t *pen, cairo_point_t *point, int num_points)
{
    cairo_status_t status;
    int num_vertices;
    int i;

    num_vertices = pen->num_vertices + num_points;
    if (num_vertices > ARRAY_LENGTH (pen->vertices_embedded) ||
	pen->vertices != pen->vertices_embedded)
    {
	cairo_pen_vertex_t *vertices;

	if (pen->vertices == pen->vertices_embedded) {
	    vertices = _cairo_malloc_ab (num_vertices,
		                         sizeof (cairo_pen_vertex_t));
	    if (vertices == NULL)
		return _cairo_error (CAIRO_STATUS_NO_MEMORY);

	    memcpy (vertices, pen->vertices,
		    pen->num_vertices * sizeof (cairo_pen_vertex_t));
	} else {
	    vertices = _cairo_realloc_ab (pen->vertices,
					  num_vertices,
					  sizeof (cairo_pen_vertex_t));
	    if (vertices == NULL)
		return _cairo_error (CAIRO_STATUS_NO_MEMORY);
	}

	pen->vertices = vertices;
    }

    pen->num_vertices = num_vertices;

    /* initialize new vertices */
    for (i=0; i < num_points; i++)
	pen->vertices[pen->num_vertices-num_points+i].point = point[i];

    status = _cairo_hull_compute (pen->vertices, &pen->num_vertices);
    if (status)
	return status;

    _cairo_pen_compute_slopes (pen);

    return CAIRO_STATUS_SUCCESS;
}
예제 #7
0
/**
 * _cairo_utf8_to_ucs4:
 * @str: an UTF-8 string
 * @len: length of @str in bytes, or -1 if it is nul-terminated.
 *   If @len is supplied and the string has an embedded nul
 *   byte, only the portion before the nul byte is converted.
 * @result: location to store a pointer to a newly allocated UTF-32
 *   string (always native endian), or %NULL. Free with free(). A 0
 *   word will be written after the last character.
 * @items_written: location to store number of 32-bit words
 *   written. (Not including the trailing 0)
 *
 * Converts a UTF-8 string to UCS-4. UCS-4 is an encoding of Unicode
 * with 1 32-bit word per character. The string is validated to
 * consist entirely of valid Unicode characters.
 *
 * Return value: %CAIRO_STATUS_SUCCESS if the entire string was
 *   successfully converted. %CAIRO_STATUS_INVALID_STRING if an
 *   invalid sequence was found.
 **/
cairo_status_t
_cairo_utf8_to_ucs4 (const char *str,
		     int	 len,
		     uint32_t  **result,
		     int	*items_written)
{
    uint32_t *str32 = NULL;
    int n_chars, i;
    const unsigned char *in;
    const unsigned char * const ustr = (const unsigned char *) str;

    in = ustr;
    n_chars = 0;
    while ((len < 0 || ustr + len - in > 0) && *in)
    {
	uint32_t wc = _utf8_get_char_extended (in, ustr + len - in);
	if (wc & 0x80000000 || !UNICODE_VALID (wc))
	    return _cairo_error (CAIRO_STATUS_INVALID_STRING);

	n_chars++;
	if (n_chars == INT_MAX)
	    return _cairo_error (CAIRO_STATUS_INVALID_STRING);

	in = UTF8_NEXT_CHAR (in);
    }

    if (result) {
	str32 = _cairo_malloc_ab (n_chars + 1, sizeof (uint32_t));
	if (!str32)
	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);

	in = ustr;
	for (i=0; i < n_chars; i++) {
	    str32[i] = _utf8_get_char (in);
	    in = UTF8_NEXT_CHAR (in);
	}
	str32[i] = 0;

	*result = str32;
    }

    if (items_written)
	*items_written = n_chars;

    return CAIRO_STATUS_SUCCESS;
}
예제 #8
0
파일: cairo-polygon.c 프로젝트: mgya/xCairo
cairo_status_t
_cairo_polygon_init_box_array (cairo_polygon_t *polygon,
			       cairo_box_t *boxes,
			       int num_boxes)
{
    int i;

    VG (VALGRIND_MAKE_MEM_UNDEFINED (polygon, sizeof (cairo_polygon_t)));

    polygon->status = CAIRO_STATUS_SUCCESS;

    polygon->num_edges = 0;

    polygon->edges = polygon->edges_embedded;
    polygon->edges_size = ARRAY_LENGTH (polygon->edges_embedded);
    if (num_boxes > ARRAY_LENGTH (polygon->edges_embedded)/2) {
	polygon->edges_size = 2 * num_boxes;
	polygon->edges = _cairo_malloc_ab (polygon->edges_size,
					   2*sizeof(cairo_edge_t));
	if (unlikely (polygon->edges == XNULL))
	    return polygon->status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
    }

    polygon->extents.p1.x = polygon->extents.p1.y = INT32_MAX;
    polygon->extents.p2.x = polygon->extents.p2.y = INT32_MIN;

    polygon->limits = XNULL;
    polygon->num_limits = 0;

    for (i = 0; i < num_boxes; i++) {
	cairo_point_t p1, p2;

	p1 = boxes[i].p1;
	p2.x = p1.x;
	p2.y = boxes[i].p2.y;
	_cairo_polygon_add_edge (polygon, &p1, &p2, 1);

	p1 = boxes[i].p2;
	p2.x = p1.x;
	p2.y = boxes[i].p1.y;
	_cairo_polygon_add_edge (polygon, &p1, &p2, 1);
    }

    return polygon->status;
}
예제 #9
0
파일: cairo-pen.c 프로젝트: 3oyka/cairo2
cairo_status_t
_cairo_pen_init_copy (cairo_pen_t *pen, cairo_pen_t *other)
{
    *pen = *other;

    pen->vertices = pen->vertices_embedded;
    if (pen->num_vertices) {
	if (pen->num_vertices > ARRAY_LENGTH (pen->vertices_embedded)) {
	    pen->vertices = _cairo_malloc_ab (pen->num_vertices,
					      sizeof (cairo_pen_vertex_t));
	    if (pen->vertices == NULL)
		return _cairo_error (CAIRO_STATUS_NO_MEMORY);
	}

	memcpy (pen->vertices, other->vertices,
		pen->num_vertices * sizeof (cairo_pen_vertex_t));
    }

    return CAIRO_STATUS_SUCCESS;
}
예제 #10
0
static cairo_hull_t *
_cairo_hull_create (cairo_pen_vertex_t *vertices, int num_vertices)
{
    int i;
    cairo_hull_t *hull;
    cairo_point_t *p, *extremum, tmp;

    extremum = &vertices[0].point;
    for (i = 1; i < num_vertices; i++) {
	p = &vertices[i].point;
	if (p->y < extremum->y || (p->y == extremum->y && p->x < extremum->x))
	    extremum = p;
    }
    /* Put the extremal point at the beginning of the array */
    tmp = *extremum;
    *extremum = vertices[0].point;
    vertices[0].point = tmp;

    hull = _cairo_malloc_ab (num_vertices, sizeof (cairo_hull_t));
    if (hull == NULL)
	return NULL;

    for (i = 0; i < num_vertices; i++) {
	hull[i].point = vertices[i].point;
	_cairo_slope_init (&hull[i].slope, &hull[0].point, &hull[i].point);

        /* give each point a unique id for later comparison */
        hull[i].id = i;

        /* Don't discard by default */
        hull[i].discard = 0;

	/* Discard all points coincident with the extremal point */
	if (i != 0 && hull[i].slope.dx == 0 && hull[i].slope.dy == 0)
	    hull[i].discard = 1;
    }

    return hull;
}
예제 #11
0
static cairo_status_t
_cairo_rectilinear_stroker_add_segment (cairo_rectilinear_stroker_t *stroker,
					const cairo_point_t	*p1,
					const cairo_point_t	*p2,
					cairo_bool_t		 is_horizontal,
					cairo_bool_t		 has_join)
{

    if (stroker->num_segments == stroker->segments_size) {
	int new_size = stroker->segments_size * 2;
	segment_t *new_segments;

	if (stroker->segments == stroker->segments_embedded) {
	    new_segments = _cairo_malloc_ab (new_size, sizeof (segment_t));
	    if (unlikely (new_segments == NULL))
		return _cairo_error (CAIRO_STATUS_NO_MEMORY);

	    memcpy (new_segments, stroker->segments,
		    stroker->num_segments * sizeof (segment_t));
	} else {
	    new_segments = _cairo_realloc_ab (stroker->segments,
					      new_size, sizeof (segment_t));
	    if (unlikely (new_segments == NULL))
		return _cairo_error (CAIRO_STATUS_NO_MEMORY);
	}

	stroker->segments_size = new_size;
	stroker->segments = new_segments;
    }

    stroker->segments[stroker->num_segments].p1 = *p1;
    stroker->segments[stroker->num_segments].p2 = *p2;
    stroker->segments[stroker->num_segments].has_join = has_join;
    stroker->segments[stroker->num_segments].is_horizontal = is_horizontal;
    stroker->num_segments++;

    return CAIRO_STATUS_SUCCESS;
}
예제 #12
0
파일: cairo-path.c 프로젝트: mgya/xCairo
static cairo_path_t *
_cairo_path_create_internal (cairo_path_fixed_t *path_fixed,
			     cairo_t		*cr,
			     cairo_bool_t	 flatten)
{
    cairo_path_t *path;

    path = xmemory_alloc (sizeof (cairo_path_t));
    if (unlikely (path == XNULL)) {
	_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
	return (cairo_path_t*) &_cairo_path_nil;
    }

    path->num_data = _cairo_path_count (path, path_fixed,
					cairo_get_tolerance (cr),
					flatten);
    if (path->num_data < 0) {
	xmemory_free (path);
	return (cairo_path_t*) &_cairo_path_nil;
    }

    if (path->num_data) {
	path->data = _cairo_malloc_ab (path->num_data,
				       sizeof (cairo_path_data_t));
	if (unlikely (path->data == XNULL)) {
	    xmemory_free (path);
	    _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
	    return (cairo_path_t*) &_cairo_path_nil;
	}

	path->status = _cairo_path_populate (path, path_fixed, cr, flatten);
    } else {
	path->data = XNULL;
	path->status = CAIRO_STATUS_SUCCESS;
    }

    return path;
}
예제 #13
0
static cairo_status_t
_cairo_rectilinear_stroker_add_segment (cairo_rectilinear_stroker_t *stroker,
					const cairo_point_t	*p1,
					const cairo_point_t	*p2,
					unsigned		 flags)
{
    if (CAIRO_INJECT_FAULT ())
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);

    if (stroker->num_segments == stroker->segments_size) {
	int new_size = stroker->segments_size * 2;
	segment_t *new_segments;

	if (stroker->segments == stroker->segments_embedded) {
	    new_segments = _cairo_malloc_ab (new_size, sizeof (segment_t));
	    if (unlikely (new_segments == NULL))
		return _cairo_error (CAIRO_STATUS_NO_MEMORY);

	    memcpy (new_segments, stroker->segments,
		    stroker->num_segments * sizeof (segment_t));
	} else {
	    new_segments = _cairo_realloc_ab (stroker->segments,
					      new_size, sizeof (segment_t));
	    if (unlikely (new_segments == NULL))
		return _cairo_error (CAIRO_STATUS_NO_MEMORY);
	}

	stroker->segments_size = new_size;
	stroker->segments = new_segments;
    }

    stroker->segments[stroker->num_segments].p1 = *p1;
    stroker->segments[stroker->num_segments].p2 = *p2;
    stroker->segments[stroker->num_segments].flags = flags;
    stroker->num_segments++;

    return CAIRO_STATUS_SUCCESS;
}
예제 #14
0
/* make room for at least one more trap */
static cairo_status_t
_cairo_traps_grow (cairo_traps_t *traps)
{
    cairo_trapezoid_t *new_traps;
    int new_size = 2 * MAX (traps->traps_size, 16);

    if (traps->traps == traps->traps_embedded) {
	new_traps = _cairo_malloc_ab (new_size, sizeof (cairo_trapezoid_t));
	if (new_traps)
	    memcpy (new_traps, traps->traps, sizeof (traps->traps_embedded));
    } else {
	new_traps = _cairo_realloc_ab (traps->traps,
	                               new_size, sizeof (cairo_trapezoid_t));
    }

    if (new_traps == NULL)
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);

    traps->traps = new_traps;
    traps->traps_size = new_size;

    return CAIRO_STATUS_SUCCESS;
}
예제 #15
0
/* make room for at least one more trap */
static cairo_bool_t
_cairo_traps_grow (cairo_traps_t *traps)
{
    cairo_trapezoid_t *new_traps;
    int new_size = 2 * MAX (traps->traps_size, 16);

    if (traps->traps == traps->traps_embedded) {
	new_traps = _cairo_malloc_ab (new_size, sizeof (cairo_trapezoid_t));
	if (new_traps != NULL)
	    memcpy (new_traps, traps->traps, sizeof (traps->traps_embedded));
    } else {
	new_traps = _cairo_realloc_ab (traps->traps,
	                               new_size, sizeof (cairo_trapezoid_t));
    }

    if (unlikely (new_traps == NULL)) {
	traps->status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
	return FALSE;
    }

    traps->traps = new_traps;
    traps->traps_size = new_size;
    return TRUE;
}
예제 #16
0
/*
 * Construct a fan around the midpoint using the vertices from pen between
 * inpt and outpt.
 */
static cairo_status_t
_tessellate_fan (cairo_stroker_t *stroker,
		 const cairo_slope_t *in_vector,
		 const cairo_slope_t *out_vector,
		 const cairo_point_t *midpt,
		 const cairo_point_t *inpt,
		 const cairo_point_t *outpt,
		 cairo_bool_t clockwise)
{
    cairo_point_t stack_points[64], *points = stack_points;
    int start, stop, step, i, npoints;
    cairo_status_t status;

    if (clockwise) {
	step  = -1;

	start = _cairo_pen_find_active_ccw_vertex_index (&stroker->pen,
							 in_vector);
	if (_cairo_slope_compare (&stroker->pen.vertices[start].slope_ccw,
				  in_vector) < 0)
	    start = _range_step (start, -1, stroker->pen.num_vertices);

	stop  = _cairo_pen_find_active_ccw_vertex_index (&stroker->pen,
							 out_vector);
	if (_cairo_slope_compare (&stroker->pen.vertices[stop].slope_cw,
				  out_vector) > 0)
	{
	    stop = _range_step (stop, 1, stroker->pen.num_vertices);
	    if (_cairo_slope_compare (&stroker->pen.vertices[stop].slope_ccw,
				      in_vector) < 0)
	    {
		goto BEVEL;
	    }
	}

	npoints = start - stop;
    } else {
	step  = 1;

	start = _cairo_pen_find_active_cw_vertex_index (&stroker->pen,
							in_vector);
	if (_cairo_slope_compare (&stroker->pen.vertices[start].slope_cw,
				  in_vector) < 0)
	    start = _range_step (start, 1, stroker->pen.num_vertices);

	stop  = _cairo_pen_find_active_cw_vertex_index (&stroker->pen,
							out_vector);
	if (_cairo_slope_compare (&stroker->pen.vertices[stop].slope_ccw,
				  out_vector) > 0)
	{
	    stop = _range_step (stop, -1, stroker->pen.num_vertices);
	    if (_cairo_slope_compare (&stroker->pen.vertices[stop].slope_cw,
				      in_vector) < 0)
	    {
		goto BEVEL;
	    }
	}

	npoints = stop - start;
    }
    stop = _range_step (stop, step, stroker->pen.num_vertices);

    if (npoints < 0)
	npoints += stroker->pen.num_vertices;
    npoints += 3;

    if (npoints <= 1)
	goto BEVEL;

    if (npoints > ARRAY_LENGTH (stack_points)) {
	points = _cairo_malloc_ab (npoints, sizeof (cairo_point_t));
	if (unlikely (points == NULL))
	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    }


    /* Construct the fan. */
    npoints = 0;
    points[npoints++] = *inpt;
    for (i = start;
	 i != stop;
	i = _range_step (i, step, stroker->pen.num_vertices))
    {
	points[npoints] = *midpt;
	_translate_point (&points[npoints], &stroker->pen.vertices[i].point);
	npoints++;
    }
    points[npoints++] = *outpt;

    if (stroker->add_external_edge != NULL) {
	for (i = 0; i < npoints - 1; i++) {
	    if (clockwise) {
		status = stroker->add_external_edge (stroker->closure,
						     &points[i], &points[i+1]);
	    } else {
		status = stroker->add_external_edge (stroker->closure,
						     &points[i+1], &points[i]);
	    }
	    if (unlikely (status))
		break;
	}
    } else {
	status = stroker->add_triangle_fan (stroker->closure,
					    midpt, points, npoints);
    }

    if (points != stack_points)
	free (points);

    return status;

BEVEL:
    /* Ensure a leak free connection... */
    if (stroker->add_external_edge != NULL) {
	if (clockwise)
	    return stroker->add_external_edge (stroker->closure, inpt, outpt);
	else
	    return stroker->add_external_edge (stroker->closure, outpt, inpt);
    } else {
	stack_points[0] = *midpt;
	stack_points[1] = *inpt;
	stack_points[2] = *outpt;
	return stroker->add_triangle (stroker->closure, stack_points);
    }
}
예제 #17
0
cairo_int_status_t
_cairo_pdf_operators_emit_stroke_style (cairo_pdf_operators_t		*pdf_operators,
					const cairo_stroke_style_t	*style,
					double				 scale)
{
    double *dash = style->dash;
    int num_dashes = style->num_dashes;
    double dash_offset = style->dash_offset;
    double line_width = style->line_width * scale;

    /* PostScript has "special needs" when it comes to zero-length
     * dash segments with butt caps. It apparently (at least
     * according to ghostscript) draws hairlines for this
     * case. That's not what the cairo semantics want, so we first
     * touch up the array to eliminate any 0.0 values that will
     * result in "on" segments.
     */
    if (num_dashes && style->line_cap == CAIRO_LINE_CAP_BUTT) {
	int i;

	/* If there's an odd number of dash values they will each get
	 * interpreted as both on and off. So we first explicitly
	 * expand the array to remove the duplicate usage so that we
	 * can modify some of the values.
	 */
	if (num_dashes % 2) {
	    dash = _cairo_malloc_abc (num_dashes, 2, sizeof (double));
	    if (unlikely (dash == NULL))
		return _cairo_error (CAIRO_STATUS_NO_MEMORY);

	    memcpy (dash, style->dash, num_dashes * sizeof (double));
	    memcpy (dash + num_dashes, style->dash, num_dashes * sizeof (double));

	    num_dashes *= 2;
	}

	for (i = 0; i < num_dashes; i += 2) {
	    if (dash[i] == 0.0) {
		/* Do not modify the dashes in-place, as we may need to also
		 * replay this stroke to an image fallback.
		 */
		if (dash == style->dash) {
		    dash = _cairo_malloc_ab (num_dashes, sizeof (double));
		    if (unlikely (dash == NULL))
			return _cairo_error (CAIRO_STATUS_NO_MEMORY);
		    memcpy (dash, style->dash, num_dashes * sizeof (double));
		}

		/* If we're at the front of the list, we first rotate
		 * two elements from the end of the list to the front
		 * of the list before folding away the 0.0. Or, if
		 * there are only two dash elements, then there is
		 * nothing at all to draw.
		 */
		if (i == 0) {
		    double last_two[2];

		    if (num_dashes == 2) {
			free (dash);
			return CAIRO_INT_STATUS_NOTHING_TO_DO;
		    }

		    /* The cases of num_dashes == 0, 1, or 3 elements
		     * cannot exist, so the rotation of 2 elements
		     * will always be safe */
		    memcpy (last_two, dash + num_dashes - 2, sizeof (last_two));
		    memmove (dash + 2, dash, (num_dashes - 2) * sizeof (double));
		    memcpy (dash, last_two, sizeof (last_two));
		    dash_offset += dash[0] + dash[1];
		    i = 2;
		}
		dash[i-1] += dash[i+1];
		num_dashes -= 2;
		memmove (dash + i, dash + i + 2, (num_dashes - i) * sizeof (double));
		/* If we might have just rotated, it's possible that
		 * we rotated a 0.0 value to the front of the list.
		 * Set i to -2 so it will get incremented to 0. */
		if (i == 2)
		    i = -2;
	    }
	}
    }

    if (!pdf_operators->has_line_style || pdf_operators->line_width != line_width) {
	_cairo_output_stream_printf (pdf_operators->stream,
				     "%f w\n",
				     line_width);
	pdf_operators->line_width = line_width;
    }

    if (!pdf_operators->has_line_style || pdf_operators->line_cap != style->line_cap) {
	_cairo_output_stream_printf (pdf_operators->stream,
				     "%d J\n",
				     _cairo_pdf_line_cap (style->line_cap));
	pdf_operators->line_cap = style->line_cap;
    }

    if (!pdf_operators->has_line_style || pdf_operators->line_join != style->line_join) {
	_cairo_output_stream_printf (pdf_operators->stream,
				     "%d j\n",
				     _cairo_pdf_line_join (style->line_join));
	pdf_operators->line_join = style->line_join;
    }

    if (num_dashes) {
	int d;

	_cairo_output_stream_printf (pdf_operators->stream, "[");
	for (d = 0; d < num_dashes; d++)
	    _cairo_output_stream_printf (pdf_operators->stream, " %f", dash[d] * scale);
	_cairo_output_stream_printf (pdf_operators->stream, "] %f d\n",
				     dash_offset * scale);
	pdf_operators->has_dashes = TRUE;
    } else if (!pdf_operators->has_line_style || pdf_operators->has_dashes) {
	_cairo_output_stream_printf (pdf_operators->stream, "[] 0.0 d\n");
	pdf_operators->has_dashes = FALSE;
    }
    if (dash != style->dash)
        free (dash);

    if (!pdf_operators->has_line_style || pdf_operators->miter_limit != style->miter_limit) {
	_cairo_output_stream_printf (pdf_operators->stream,
				     "%f M ",
				     style->miter_limit < 1.0 ? 1.0 : style->miter_limit);
	pdf_operators->miter_limit = style->miter_limit;
    }
    pdf_operators->has_line_style = TRUE;

    return _cairo_output_stream_get_status (pdf_operators->stream);
}
예제 #18
0
/*
 * Construct a fan around the midpoint using the vertices from pen between
 * inpt and outpt.
 */
static cairo_status_t
_tessellate_fan (cairo_stroker_t *stroker,
		 const cairo_slope_t *in_vector,
		 const cairo_slope_t *out_vector,
		 const cairo_point_t *midpt,
		 const cairo_point_t *inpt,
		 const cairo_point_t *outpt,
		 cairo_bool_t clockwise)
{
    cairo_point_t stack_points[64], *points = stack_points;
    cairo_pen_t *pen = &stroker->pen;
    int start, stop, num_points = 0;
    cairo_status_t status;

    if (stroker->has_bounds &&
	! _cairo_box_contains_point (&stroker->bounds, midpt))
	goto BEVEL;

    assert (stroker->pen.num_vertices);

    if (clockwise) {
	_cairo_pen_find_active_ccw_vertices (pen,
					     in_vector, out_vector,
					     &start, &stop);
	if (stroker->add_external_edge) {
	    cairo_point_t last;
	    last = *inpt;
	    while (start != stop) {
		cairo_point_t p = *midpt;
		_translate_point (&p, &pen->vertices[start].point);

		status = stroker->add_external_edge (stroker->closure,
						     &last, &p);
		if (unlikely (status))
		    return status;
		last = p;

		if (start-- == 0)
		    start += pen->num_vertices;
	    }
	    status = stroker->add_external_edge (stroker->closure,
						 &last, outpt);
	} else {
	    if (start == stop)
		goto BEVEL;

	    num_points = stop - start;
	    if (num_points < 0)
		num_points += pen->num_vertices;
	    num_points += 2;
	    if (num_points > ARRAY_LENGTH(stack_points)) {
		points = _cairo_malloc_ab (num_points, sizeof (cairo_point_t));
		if (unlikely (points == NULL))
		    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
	    }

	    points[0] = *inpt;
	    num_points = 1;
	    while (start != stop) {
		points[num_points] = *midpt;
		_translate_point (&points[num_points], &pen->vertices[start].point);
		num_points++;

		if (start-- == 0)
		    start += pen->num_vertices;
	    }
	    points[num_points++] = *outpt;
	}
    } else {
	_cairo_pen_find_active_cw_vertices (pen,
					    in_vector, out_vector,
					    &start, &stop);
	if (stroker->add_external_edge) {
	    cairo_point_t last;
	    last = *inpt;
	    while (start != stop) {
		cairo_point_t p = *midpt;
		_translate_point (&p, &pen->vertices[start].point);

		status = stroker->add_external_edge (stroker->closure,
						     &p, &last);
		if (unlikely (status))
		    return status;
		last = p;

		if (++start == pen->num_vertices)
		    start = 0;
	    }
	    status = stroker->add_external_edge (stroker->closure,
						 outpt, &last);
	} else {
	    if (start == stop)
		goto BEVEL;

	    num_points = stop - start;
	    if (num_points < 0)
		num_points += pen->num_vertices;
	    num_points += 2;
	    if (num_points > ARRAY_LENGTH(stack_points)) {
		points = _cairo_malloc_ab (num_points, sizeof (cairo_point_t));
		if (unlikely (points == NULL))
		    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
	    }

	    points[0] = *inpt;
	    num_points = 1;
	    while (start != stop) {
		points[num_points] = *midpt;
		_translate_point (&points[num_points], &pen->vertices[start].point);
		num_points++;

		if (++start == pen->num_vertices)
		    start = 0;
	    }
	    points[num_points++] = *outpt;
	}
    }

    if (num_points) {
	status = stroker->add_triangle_fan (stroker->closure,
					    midpt, points, num_points);
    }

    if (points != stack_points)
	free (points);

    return status;

BEVEL:
    /* Ensure a leak free connection... */
    if (stroker->add_external_edge != NULL) {
	if (clockwise)
	    return stroker->add_external_edge (stroker->closure, inpt, outpt);
	else
	    return stroker->add_external_edge (stroker->closure, outpt, inpt);
    } else {
	stack_points[0] = *midpt;
	stack_points[1] = *inpt;
	stack_points[2] = *outpt;
	return stroker->add_triangle (stroker->closure, stack_points);
    }
}
예제 #19
0
cairo_status_t
_cairo_surface_fallback_fill_rectangles (cairo_surface_t         *surface,
					 cairo_operator_t	  op,
					 const cairo_color_t	 *color,
					 cairo_rectangle_int_t   *rects,
					 int			  num_rects)
{
    fallback_state_t state;
    cairo_rectangle_int_t *offset_rects = NULL;
    cairo_status_t status;
    int x1, y1, x2, y2;
    int i;

    assert (! surface->is_snapshot);

    if (num_rects <= 0)
	return CAIRO_STATUS_SUCCESS;

    /* Compute the bounds of the rectangles, so that we know what area of the
     * destination surface to fetch
     */
    x1 = rects[0].x;
    y1 = rects[0].y;
    x2 = rects[0].x + rects[0].width;
    y2 = rects[0].y + rects[0].height;

    for (i = 1; i < num_rects; i++) {
	if (rects[i].x < x1)
	    x1 = rects[i].x;
	if (rects[i].y < y1)
	    y1 = rects[i].y;

	if ((int)(rects[i].x + rects[i].width) > x2)
	    x2 = rects[i].x + rects[i].width;
	if ((int)(rects[i].y + rects[i].height) > y2)
	    y2 = rects[i].y + rects[i].height;
    }

    status = _fallback_init (&state, surface, x1, y1, x2 - x1, y2 - y1);
    if (status) {
	if (status == CAIRO_INT_STATUS_NOTHING_TO_DO)
	    return CAIRO_STATUS_SUCCESS;
	return status;
    }

    /* If the fetched image isn't at 0,0, we need to offset the rectangles */

    if (state.image_rect.x != 0 || state.image_rect.y != 0) {
	offset_rects = _cairo_malloc_ab (num_rects, sizeof (cairo_rectangle_int_t));
	if (offset_rects == NULL) {
	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
	    goto DONE;
	}

	for (i = 0; i < num_rects; i++) {
	    offset_rects[i].x = rects[i].x - state.image_rect.x;
	    offset_rects[i].y = rects[i].y - state.image_rect.y;
	    offset_rects[i].width = rects[i].width;
	    offset_rects[i].height = rects[i].height;
	}

	rects = offset_rects;
    }

    status = _cairo_surface_fill_rectangles (&state.image->base,
					     op, color,
					     rects, num_rects);

    free (offset_rects);

 DONE:
    _fallback_fini (&state);

    return status;
}
static cairo_status_t
_cairo_recording_surface_replay_internal (cairo_surface_t	     *surface,
					  const cairo_rectangle_int_t *surface_extents,
					  cairo_surface_t	     *target,
					  cairo_recording_replay_type_t type,
					  cairo_recording_region_type_t region)
{
    cairo_recording_surface_t *recording_surface;
    cairo_command_t **elements;
    int i, num_elements;
    cairo_int_status_t status;
    cairo_surface_wrapper_t wrapper;

    if (unlikely (surface->status))
	return surface->status;

    if (unlikely (target->status))
	return target->status;

    if (unlikely (surface->finished))
	return _cairo_error (CAIRO_STATUS_SURFACE_FINISHED);

    if (surface->is_clear)
	return CAIRO_STATUS_SUCCESS;

    assert (_cairo_surface_is_recording (surface));

    _cairo_surface_wrapper_init (&wrapper, target);
    _cairo_surface_wrapper_set_extents (&wrapper, surface_extents);

    recording_surface = (cairo_recording_surface_t *) surface;
    status = CAIRO_STATUS_SUCCESS;

    num_elements = recording_surface->commands.num_elements;
    elements = _cairo_array_index (&recording_surface->commands, 0);

    for (i = recording_surface->replay_start_idx; i < num_elements; i++) {
	cairo_command_t *command = elements[i];

	if (type == CAIRO_RECORDING_REPLAY && region != CAIRO_RECORDING_REGION_ALL) {
	    if (command->header.region != region)
		continue;
        }

	switch (command->header.type) {
	case CAIRO_COMMAND_PAINT:
	    status = _cairo_surface_wrapper_paint (&wrapper,
						   command->header.op,
						   &command->paint.source.base,
						   _clip (command));
	    break;

	case CAIRO_COMMAND_MASK:
	    status = _cairo_surface_wrapper_mask (&wrapper,
						  command->header.op,
						  &command->mask.source.base,
						  &command->mask.mask.base,
						  _clip (command));
	    break;

	case CAIRO_COMMAND_STROKE:
	{
	    status = _cairo_surface_wrapper_stroke (&wrapper,
						    command->header.op,
						    &command->stroke.source.base,
						    &command->stroke.path,
						    &command->stroke.style,
						    &command->stroke.ctm,
						    &command->stroke.ctm_inverse,
						    command->stroke.tolerance,
						    command->stroke.antialias,
						    _clip (command));
	    break;
	}
	case CAIRO_COMMAND_FILL:
	{
	    cairo_command_t *stroke_command;

	    stroke_command = NULL;
	    if (type != CAIRO_RECORDING_CREATE_REGIONS && i < num_elements - 1)
		stroke_command = elements[i + 1];

	    if (stroke_command != NULL &&
		type == CAIRO_RECORDING_REPLAY &&
		region != CAIRO_RECORDING_REGION_ALL)
	    {
		if (stroke_command->header.region != region)
		    stroke_command = NULL;
	    }

	    if (stroke_command != NULL &&
		stroke_command->header.type == CAIRO_COMMAND_STROKE &&
		_cairo_path_fixed_is_equal (&command->fill.path,
					    &stroke_command->stroke.path))
	    {
		status = _cairo_surface_wrapper_fill_stroke (&wrapper,
							     command->header.op,
							     &command->fill.source.base,
							     command->fill.fill_rule,
							     command->fill.tolerance,
							     command->fill.antialias,
							     &command->fill.path,
							     stroke_command->header.op,
							     &stroke_command->stroke.source.base,
							     &stroke_command->stroke.style,
							     &stroke_command->stroke.ctm,
							     &stroke_command->stroke.ctm_inverse,
							     stroke_command->stroke.tolerance,
							     stroke_command->stroke.antialias,
							     _clip (command));
		i++;
	    }
	    else
	    {
		status = _cairo_surface_wrapper_fill (&wrapper,
						      command->header.op,
						      &command->fill.source.base,
						      &command->fill.path,
						      command->fill.fill_rule,
						      command->fill.tolerance,
						      command->fill.antialias,
						      _clip (command));
	    }
	    break;
	}
	case CAIRO_COMMAND_SHOW_TEXT_GLYPHS:
	{
	    cairo_glyph_t *glyphs = command->show_text_glyphs.glyphs;
	    cairo_glyph_t *glyphs_copy;
	    int num_glyphs = command->show_text_glyphs.num_glyphs;

            /* show_text_glyphs is special because _cairo_surface_show_text_glyphs is allowed
	     * to modify the glyph array that's passed in.  We must always
	     * copy the array before handing it to the backend.
	     */
	    glyphs_copy = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
	    if (unlikely (glyphs_copy == NULL)) {
		status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
		break;
	    }

	    memcpy (glyphs_copy, glyphs, sizeof (cairo_glyph_t) * num_glyphs);

	    status = _cairo_surface_wrapper_show_text_glyphs (&wrapper,
							      command->header.op,
							      &command->show_text_glyphs.source.base,
							      command->show_text_glyphs.utf8, command->show_text_glyphs.utf8_len,
							      glyphs_copy, num_glyphs,
							      command->show_text_glyphs.clusters, command->show_text_glyphs.num_clusters,
							      command->show_text_glyphs.cluster_flags,
							      command->show_text_glyphs.scaled_font,
							      _clip (command));
	    free (glyphs_copy);
	    break;
	}
	default:
	    ASSERT_NOT_REACHED;
	}

	if (type == CAIRO_RECORDING_CREATE_REGIONS) {
	    if (status == CAIRO_STATUS_SUCCESS) {
		command->header.region = CAIRO_RECORDING_REGION_NATIVE;
	    } else if (status == CAIRO_INT_STATUS_IMAGE_FALLBACK) {
		command->header.region = CAIRO_RECORDING_REGION_IMAGE_FALLBACK;
		status = CAIRO_STATUS_SUCCESS;
	    } else {
		assert (_cairo_status_is_error (status));
	    }
	}

	if (unlikely (status))
	    break;
    }

    /* free up any caches */
    for (i = recording_surface->replay_start_idx; i < num_elements; i++) {
	cairo_command_t *command = elements[i];

	_cairo_clip_drop_cache (&command->header.clip);
    }

    _cairo_surface_wrapper_fini (&wrapper);

    return _cairo_surface_set_error (surface, status);
}
예제 #21
0
cairo_status_t
_cairo_surface_wrapper_show_text_glyphs (cairo_surface_wrapper_t *wrapper,
					 cairo_operator_t	     op,
					 const cairo_pattern_t	    *source,
					 const char		    *utf8,
					 int			     utf8_len,
					 const cairo_glyph_t	    *glyphs,
					 int			     num_glyphs,
					 const cairo_text_cluster_t *clusters,
					 int			     num_clusters,
					 cairo_text_cluster_flags_t  cluster_flags,
					 cairo_scaled_font_t	    *scaled_font,
					 const cairo_clip_t	    *clip)
{
    cairo_status_t status;
    cairo_clip_t *dev_clip;
    cairo_glyph_t stack_glyphs [CAIRO_STACK_ARRAY_LENGTH(cairo_glyph_t)];
    cairo_glyph_t *dev_glyphs = stack_glyphs;
    cairo_scaled_font_t *dev_scaled_font = scaled_font;
    cairo_pattern_union_t source_copy;
    cairo_font_options_t options;

    if (unlikely (wrapper->target->status))
	return wrapper->target->status;

    dev_clip = _cairo_surface_wrapper_get_clip (wrapper, clip);
    if (_cairo_clip_is_all_clipped (dev_clip))
	return CAIRO_INT_STATUS_NOTHING_TO_DO;

    cairo_surface_get_font_options (wrapper->target, &options);
    cairo_font_options_merge (&options, &scaled_font->options);

    if (wrapper->needs_transform) {
	cairo_matrix_t m;
	int i;

	_cairo_surface_wrapper_get_transform (wrapper, &m);

	if (! _cairo_matrix_is_translation (&wrapper->transform)) {
	    cairo_matrix_t ctm;

	    /* XXX No device-transform? A bug in the tangle of layers? */
	    _cairo_matrix_multiply (&ctm,
				    &wrapper->transform,
				    &scaled_font->ctm);
	    dev_scaled_font = cairo_scaled_font_create (scaled_font->font_face,
							&scaled_font->font_matrix,
							&ctm, &options);
	}

	if (num_glyphs > ARRAY_LENGTH (stack_glyphs)) {
	    dev_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
	    if (unlikely (dev_glyphs == NULL)) {
		status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
		goto FINISH;
	    }
	}

	for (i = 0; i < num_glyphs; i++) {
	    dev_glyphs[i] = glyphs[i];
	    cairo_matrix_transform_point (&m,
					  &dev_glyphs[i].x,
					  &dev_glyphs[i].y);
	}

	status = cairo_matrix_invert (&m);
	assert (status == CAIRO_STATUS_SUCCESS);

	_copy_transformed_pattern (&source_copy.base, source, &m);
	source = &source_copy.base;
    } else {
	if (! cairo_font_options_equal (&options, &scaled_font->options)) {
	    dev_scaled_font = cairo_scaled_font_create (scaled_font->font_face,
							&scaled_font->font_matrix,
							&scaled_font->ctm,
							&options);
	}

	/* show_text_glyphs is special because _cairo_surface_show_text_glyphs is allowed
	 * to modify the glyph array that's passed in.  We must always
	 * copy the array before handing it to the backend.
	 */
	if (num_glyphs > ARRAY_LENGTH (stack_glyphs)) {
	    dev_glyphs = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
	    if (unlikely (dev_glyphs == NULL)) {
		status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
		goto FINISH;
	    }
	}

	memcpy (dev_glyphs, glyphs, sizeof (cairo_glyph_t) * num_glyphs);
    }

    status = _cairo_surface_show_text_glyphs (wrapper->target, op, source,
					      utf8, utf8_len,
					      dev_glyphs, num_glyphs,
					      clusters, num_clusters,
					      cluster_flags,
					      dev_scaled_font,
					      dev_clip);
 FINISH:
    _cairo_clip_destroy (dev_clip);
    if (dev_glyphs != stack_glyphs)
	free (dev_glyphs);
    if (dev_scaled_font != scaled_font)
	cairo_scaled_font_destroy (dev_scaled_font);
    return status;
}
예제 #22
0
cairo_int_status_t
_cairo_gl_gradient_create (cairo_gl_context_t           *ctx,
			   unsigned int                  n_stops,
			   const cairo_gradient_stop_t  *stops,
			   cairo_gl_gradient_t         **gradient_out)
{
    unsigned long hash;
    cairo_gl_gradient_t *gradient;
    cairo_status_t status;
    int tex_width;
    GLint internal_format;
    void *data;

    if ((unsigned int) ctx->max_texture_size / 2 <= n_stops)
	return CAIRO_INT_STATUS_UNSUPPORTED;

    hash = _cairo_gl_gradient_hash (n_stops, stops);

    gradient = _cairo_gl_gradient_lookup (ctx, hash, n_stops, stops);
    if (gradient) {
	*gradient_out = _cairo_gl_gradient_reference (gradient);
	return CAIRO_STATUS_SUCCESS;
    }

    gradient = _cairo_malloc (sizeof (cairo_gl_gradient_t) + sizeof (cairo_gradient_stop_t) * (n_stops - 1));
    if (gradient == NULL)
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);

    tex_width = _cairo_gl_gradient_sample_width (n_stops, stops);
    if (tex_width > ctx->max_texture_size)
	tex_width = ctx->max_texture_size;

    CAIRO_REFERENCE_COUNT_INIT (&gradient->ref_count, 2);
    gradient->cache_entry.hash = hash;
    gradient->cache_entry.size = tex_width;
    gradient->device = &ctx->base;
    gradient->n_stops = n_stops;
    gradient->stops = gradient->stops_embedded;
    memcpy (gradient->stops_embedded, stops, n_stops * sizeof (cairo_gradient_stop_t));

    glGenTextures (1, &gradient->tex);
    _cairo_gl_context_activate (ctx, CAIRO_GL_TEX_TEMP);
    glBindTexture (ctx->tex_target, gradient->tex);

    data = _cairo_malloc_ab (tex_width, sizeof (uint32_t));
    if (unlikely (data == NULL)) {
	status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
	goto cleanup_gradient;
    }

    status = _cairo_gl_gradient_render (ctx, n_stops, stops, data, tex_width);
    if (unlikely (status))
	goto cleanup_data;

    /*
     * In OpenGL ES 2.0 no format conversion is allowed i.e. 'internalFormat'
     * must match 'format' in glTexImage2D.
     */
    if (_cairo_gl_get_flavor () == CAIRO_GL_FLAVOR_ES3 ||
	_cairo_gl_get_flavor () == CAIRO_GL_FLAVOR_ES2)
	internal_format = GL_BGRA;
    else
	internal_format = GL_RGBA;

    glTexImage2D (ctx->tex_target, 0, internal_format, tex_width, 1, 0,
		  GL_BGRA, GL_UNSIGNED_BYTE, data);

    free (data);

    /* we ignore errors here and just return an uncached gradient */
    if (unlikely (_cairo_cache_insert (&ctx->gradients, &gradient->cache_entry)))
	CAIRO_REFERENCE_COUNT_INIT (&gradient->ref_count, 1);

    *gradient_out = gradient;
    return CAIRO_STATUS_SUCCESS;

cleanup_data:
    free (data);
cleanup_gradient:
    free (gradient);
    return status;
}
예제 #23
0
static cairo_status_t
_cairo_gl_gradient_render (const cairo_gl_context_t    *ctx,
			   unsigned int                 n_stops,
			   const cairo_gradient_stop_t *stops,
			   void                        *bytes,
			   int                          width)
{
    pixman_image_t *gradient, *image;
    pixman_gradient_stop_t pixman_stops_stack[32];
    pixman_gradient_stop_t *pixman_stops;
    pixman_point_fixed_t p1, p2;
    unsigned int i;
    pixman_format_code_t gradient_pixman_format;

    /*
     * Ensure that the order of the gradient's components in memory is BGRA.
     * This is done so that the gradient's pixel data is always suitable for
     * texture upload using format=GL_BGRA and type=GL_UNSIGNED_BYTE.
     */
    if (_cairo_is_little_endian ())
	gradient_pixman_format = PIXMAN_a8r8g8b8;
    else
	gradient_pixman_format = PIXMAN_b8g8r8a8;

    pixman_stops = pixman_stops_stack;
    if (unlikely (n_stops > ARRAY_LENGTH (pixman_stops_stack))) {
	pixman_stops = _cairo_malloc_ab (n_stops,
					 sizeof (pixman_gradient_stop_t));
	if (unlikely (pixman_stops == NULL))
	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    }

    for (i = 0; i < n_stops; i++) {
	pixman_stops[i].x = _cairo_fixed_16_16_from_double (stops[i].offset);
	pixman_stops[i].color.red   = stops[i].color.red_short;
	pixman_stops[i].color.green = stops[i].color.green_short;
	pixman_stops[i].color.blue  = stops[i].color.blue_short;
	pixman_stops[i].color.alpha = stops[i].color.alpha_short;
    }

    p1.x = _cairo_fixed_16_16_from_double (0.5);
    p1.y = 0;
    p2.x = _cairo_fixed_16_16_from_double (width - 0.5);
    p2.y = 0;

    gradient = pixman_image_create_linear_gradient (&p1, &p2,
						    pixman_stops,
						    n_stops);
    if (pixman_stops != pixman_stops_stack)
	free (pixman_stops);

    if (unlikely (gradient == NULL))
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);

    pixman_image_set_filter (gradient, PIXMAN_FILTER_BILINEAR, NULL, 0);
    pixman_image_set_repeat (gradient, PIXMAN_REPEAT_PAD);

    image = pixman_image_create_bits (gradient_pixman_format, width, 1,
				      bytes, sizeof(uint32_t)*width);
    if (unlikely (image == NULL)) {
	pixman_image_unref (gradient);
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    }

    pixman_image_composite32 (PIXMAN_OP_SRC,
			      gradient, NULL, image,
			      0, 0,
			      0, 0,
			      0, 0,
			      width, 1);

    pixman_image_unref (gradient);
    pixman_image_unref (image);

    /* We need to fudge pixel 0 to hold the left-most color stop and not
     * the neareset stop to the zeroth pixel centre in order to correctly
     * populate the border color. For completeness, do both edges.
     */
    ((uint32_t*)bytes)[0] = color_stop_to_pixel(&stops[0]);
    ((uint32_t*)bytes)[width-1] = color_stop_to_pixel(&stops[n_stops-1]);

    return CAIRO_STATUS_SUCCESS;
}
static cairo_int_status_t
_cairo_tee_surface_show_text_glyphs (void		    *abstract_surface,
				     cairo_operator_t	     op,
				     const cairo_pattern_t  *source,
				     const char		    *utf8,
				     int		     utf8_len,
				     cairo_glyph_t	    *glyphs,
				     int		     num_glyphs,
				     const cairo_text_cluster_t *clusters,
				     int		     num_clusters,
				     cairo_text_cluster_flags_t cluster_flags,
				     cairo_scaled_font_t    *scaled_font,
				     cairo_clip_t	    *clip)
{
    cairo_tee_surface_t *surface = abstract_surface;
    cairo_surface_wrapper_t *slaves;
    int n, num_slaves;
    cairo_status_t status;
    cairo_glyph_t *glyphs_copy;
    const cairo_pattern_t *matched_source;
    cairo_surface_pattern_t temp;

    /* XXX: This copying is ugly. */
    glyphs_copy = _cairo_malloc_ab (num_glyphs, sizeof (cairo_glyph_t));
    if (unlikely (glyphs_copy == NULL))
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);

    memcpy (glyphs_copy, glyphs, sizeof (cairo_glyph_t) * num_glyphs);
    matched_source = _cairo_tee_surface_match_source (surface, source, 0, &surface->master, &temp);
    status = _cairo_surface_wrapper_show_text_glyphs (&surface->master, op,
                              matched_source,
						      utf8, utf8_len,
						      glyphs_copy, num_glyphs,
						      clusters, num_clusters,
						      cluster_flags,
						      scaled_font,
						      clip);
    if (matched_source == &temp.base) {
        _cairo_pattern_fini (&temp.base);
    }
    if (unlikely (status))
	goto CLEANUP;

    num_slaves = _cairo_array_num_elements (&surface->slaves);
    slaves = _cairo_array_index (&surface->slaves, 0);
    for (n = 0; n < num_slaves; n++) {
	memcpy (glyphs_copy, glyphs, sizeof (cairo_glyph_t) * num_glyphs);
      matched_source = _cairo_tee_surface_match_source (surface, source, n + 1, &slaves[n], &temp);
	status = _cairo_surface_wrapper_show_text_glyphs (&slaves[n], op,
	                          matched_source,
							  utf8, utf8_len,
							  glyphs_copy, num_glyphs,
							  clusters, num_clusters,
							  cluster_flags,
							  scaled_font,
							  clip);
        if (matched_source == &temp.base) {
            _cairo_pattern_fini (&temp.base);
        }
	if (unlikely (status))
	    goto CLEANUP;
    }

  CLEANUP:
    free (glyphs_copy);
    return status;
}
static cairo_int_status_t
_cairo_recording_surface_show_text_glyphs (void				*abstract_surface,
					   cairo_operator_t		 op,
					   const cairo_pattern_t	*source,
					   const char			*utf8,
					   int				 utf8_len,
					   cairo_glyph_t		*glyphs,
					   int				 num_glyphs,
					   const cairo_text_cluster_t	*clusters,
					   int				 num_clusters,
					   cairo_text_cluster_flags_t	 cluster_flags,
					   cairo_scaled_font_t		*scaled_font,
					   cairo_clip_t			*clip)
{
    cairo_status_t status;
    cairo_recording_surface_t *recording_surface = abstract_surface;
    cairo_command_show_text_glyphs_t *command;

    command = malloc (sizeof (cairo_command_show_text_glyphs_t));
    if (unlikely (command == NULL))
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);

    status = _command_init (recording_surface,
			    &command->header, CAIRO_COMMAND_SHOW_TEXT_GLYPHS,
			    op, clip);
    if (unlikely (status))
	goto CLEANUP_COMMAND;

    status = _cairo_pattern_init_snapshot (&command->source.base, source);
    if (unlikely (status))
	goto CLEANUP_COMMAND;

    command->utf8 = NULL;
    command->utf8_len = utf8_len;
    command->glyphs = NULL;
    command->num_glyphs = num_glyphs;
    command->clusters = NULL;
    command->num_clusters = num_clusters;

    if (utf8_len) {
	command->utf8 = malloc (utf8_len);
	if (unlikely (command->utf8 == NULL)) {
	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
	    goto CLEANUP_ARRAYS;
	}
	memcpy (command->utf8, utf8, utf8_len);
    }
    if (num_glyphs) {
	command->glyphs = _cairo_malloc_ab (num_glyphs, sizeof (glyphs[0]));
	if (unlikely (command->glyphs == NULL)) {
	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
	    goto CLEANUP_ARRAYS;
	}
	memcpy (command->glyphs, glyphs, sizeof (glyphs[0]) * num_glyphs);
    }
    if (num_clusters) {
	command->clusters = _cairo_malloc_ab (num_clusters, sizeof (clusters[0]));
	if (unlikely (command->clusters == NULL)) {
	    status = _cairo_error (CAIRO_STATUS_NO_MEMORY);
	    goto CLEANUP_ARRAYS;
	}
	memcpy (command->clusters, clusters, sizeof (clusters[0]) * num_clusters);
    }

    command->cluster_flags = cluster_flags;

    command->scaled_font = cairo_scaled_font_reference (scaled_font);

    status = _cairo_array_append (&recording_surface->commands, &command);
    if (unlikely (status))
	goto CLEANUP_SCALED_FONT;

    return CAIRO_STATUS_SUCCESS;

  CLEANUP_SCALED_FONT:
    cairo_scaled_font_destroy (command->scaled_font);
  CLEANUP_ARRAYS:
    free (command->utf8);
    free (command->glyphs);
    free (command->clusters);

    _cairo_pattern_fini (&command->source.base);
  CLEANUP_COMMAND:
    _cairo_clip_fini (&command->header.clip);
    free (command);
    return status;
}
cairo_status_t
_cairo_bentley_ottmann_tessellate_boxes (const cairo_boxes_t *in,
					 cairo_fill_rule_t fill_rule,
					 cairo_boxes_t *out)
{
    rectangle_t stack_rectangles[CAIRO_STACK_ARRAY_LENGTH (rectangle_t)];
    rectangle_t *stack_rectangles_ptrs[ARRAY_LENGTH (stack_rectangles) + 3];
    rectangle_t *rectangles, **rectangles_ptrs;
    rectangle_t *stack_rectangles_chain[CAIRO_STACK_ARRAY_LENGTH (rectangle_t *) ];
    rectangle_t **rectangles_chain = NULL;
    const struct _cairo_boxes_chunk *chunk;
    cairo_status_t status;
    int i, j, y_min, y_max;

    if (unlikely (in->num_boxes == 0)) {
	_cairo_boxes_clear (out);
	return CAIRO_STATUS_SUCCESS;
    }

    if (in->num_boxes == 1) {
	if (in == out) {
	    cairo_box_t *box = &in->chunks.base[0];

	    if (box->p1.x > box->p2.x) {
		cairo_fixed_t tmp = box->p1.x;
		box->p1.x = box->p2.x;
		box->p2.x = tmp;
	    }
	} else {
	    cairo_box_t box = in->chunks.base[0];

	    if (box.p1.x > box.p2.x) {
		cairo_fixed_t tmp = box.p1.x;
		box.p1.x = box.p2.x;
		box.p2.x = tmp;
	    }

	    _cairo_boxes_clear (out);
	    status = _cairo_boxes_add (out, CAIRO_ANTIALIAS_DEFAULT, &box);
	    assert (status == CAIRO_STATUS_SUCCESS);
	}
	return CAIRO_STATUS_SUCCESS;
    }

    y_min = INT_MAX; y_max = INT_MIN;
    for (chunk = &in->chunks; chunk != NULL; chunk = chunk->next) {
	const cairo_box_t *box = chunk->base;
	for (i = 0; i < chunk->count; i++) {
	    if (box[i].p1.y < y_min)
		y_min = box[i].p1.y;
	    if (box[i].p1.y > y_max)
		y_max = box[i].p1.y;
	}
    }
    y_min = _cairo_fixed_integer_floor (y_min);
    y_max = _cairo_fixed_integer_floor (y_max) + 1;
    y_max -= y_min;

    if (y_max < in->num_boxes) {
	rectangles_chain = stack_rectangles_chain;
	if (y_max > ARRAY_LENGTH (stack_rectangles_chain)) {
	    rectangles_chain = _cairo_malloc_ab (y_max, sizeof (rectangle_t *));
	    if (unlikely (rectangles_chain == NULL))
		return _cairo_error (CAIRO_STATUS_NO_MEMORY);
	}
	memset (rectangles_chain, 0, y_max * sizeof (rectangle_t*));
    }

    rectangles = stack_rectangles;
    rectangles_ptrs = stack_rectangles_ptrs;
    if (in->num_boxes > ARRAY_LENGTH (stack_rectangles)) {
	rectangles = _cairo_malloc_ab_plus_c (in->num_boxes,
					      sizeof (rectangle_t) +
					      sizeof (rectangle_t *),
					      3*sizeof (rectangle_t *));
	if (unlikely (rectangles == NULL)) {
	    if (rectangles_chain != stack_rectangles_chain)
		free (rectangles_chain);
	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
	}

	rectangles_ptrs = (rectangle_t **) (rectangles + in->num_boxes);
    }

    j = 0;
    for (chunk = &in->chunks; chunk != NULL; chunk = chunk->next) {
	const cairo_box_t *box = chunk->base;
	for (i = 0; i < chunk->count; i++) {
	    int h;

	    if (box[i].p1.x < box[i].p2.x) {
		rectangles[j].left.x = box[i].p1.x;
		rectangles[j].left.dir = 1;

		rectangles[j].right.x = box[i].p2.x;
		rectangles[j].right.dir = -1;
	    } else {
		rectangles[j].right.x = box[i].p1.x;
		rectangles[j].right.dir = 1;

		rectangles[j].left.x = box[i].p2.x;
		rectangles[j].left.dir = -1;
	    }

	    rectangles[j].left.right = NULL;
	    rectangles[j].right.right = NULL;

	    rectangles[j].top = box[i].p1.y;
	    rectangles[j].bottom = box[i].p2.y;

	    if (rectangles_chain) {
		h = _cairo_fixed_integer_floor (box[i].p1.y) - y_min;
		rectangles[j].left.next = (edge_t *)rectangles_chain[h];
		rectangles_chain[h] = &rectangles[j];
	    } else {
		rectangles_ptrs[j+2] = &rectangles[j];
	    }
	    j++;
	}
    }

    if (rectangles_chain) {
	j = 2;
	for (y_min = 0; y_min < y_max; y_min++) {
	    rectangle_t *r;
	    int start = j;
	    for (r = rectangles_chain[y_min]; r; r = (rectangle_t *)r->left.next)
		rectangles_ptrs[j++] = r;
	    if (j > start + 1)
		_rectangle_sort (rectangles_ptrs + start, j - start);
	}

	if (rectangles_chain != stack_rectangles_chain)
	    free (rectangles_chain);

	j -= 2;
    } else {
	_rectangle_sort (rectangles_ptrs + 2, j);
    }

    _cairo_boxes_clear (out);
    status = _cairo_bentley_ottmann_tessellate_rectangular (rectangles_ptrs+2, j,
							    fill_rule,
							    FALSE, out);
    if (rectangles != stack_rectangles)
	free (rectangles);

    return status;
}
예제 #27
0
cairo_rectangle_list_t *
_cairo_clip_copy_rectangle_list (cairo_clip_t *clip, cairo_gstate_t *gstate)
{
    cairo_rectangle_list_t *list;
    cairo_rectangle_t *rectangles = NULL;
    int n_boxes = 0;

    if (clip->all_clipped)
	goto DONE;

    if (clip->path || clip->surface) {
	_cairo_error_throw (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE);
	return (cairo_rectangle_list_t*) &_cairo_rectangles_not_representable;
    }

    if (clip->has_region) {
	cairo_box_int_t *boxes;
        int i;

	if (_cairo_region_get_boxes (&clip->region, &n_boxes, &boxes))
	    return (cairo_rectangle_list_t*) &_cairo_rectangles_nil;

	if (n_boxes) {
	    rectangles = _cairo_malloc_ab (n_boxes, sizeof (cairo_rectangle_t));
	    if (rectangles == NULL) {
		_cairo_region_boxes_fini (&clip->region, boxes);
		_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
		return (cairo_rectangle_list_t*) &_cairo_rectangles_nil;
	    }

	    for (i = 0; i < n_boxes; ++i) {
		cairo_rectangle_int_t clip_rect = { boxes[i].p1.x, boxes[i].p1.y,
						    boxes[i].p2.x - boxes[i].p1.x,
						    boxes[i].p2.y - boxes[i].p1.y };

		if (!_cairo_clip_int_rect_to_user(gstate, &clip_rect, &rectangles[i])) {
		    _cairo_error_throw (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE);
		    _cairo_region_boxes_fini (&clip->region, boxes);
		    free (rectangles);
		    return (cairo_rectangle_list_t*) &_cairo_rectangles_not_representable;
		}
	    }
	}

	_cairo_region_boxes_fini (&clip->region, boxes);
    } else {
        cairo_rectangle_int_t extents;

	n_boxes = 1;

	rectangles = malloc(sizeof (cairo_rectangle_t));
	if (rectangles == NULL) {
	    _cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
	    return (cairo_rectangle_list_t*) &_cairo_rectangles_nil;
	}

	if (_cairo_surface_get_extents (_cairo_gstate_get_target (gstate), &extents) ||
	    !_cairo_clip_int_rect_to_user(gstate, &extents, rectangles))
	{
	    _cairo_error_throw (CAIRO_STATUS_CLIP_NOT_REPRESENTABLE);
	    free (rectangles);
	    return (cairo_rectangle_list_t*) &_cairo_rectangles_not_representable;
	}
    }

 DONE:
    list = malloc (sizeof (cairo_rectangle_list_t));
    if (list == NULL) {
	_cairo_error_throw (CAIRO_STATUS_NO_MEMORY);
        free (rectangles);
        return (cairo_rectangle_list_t*) &_cairo_rectangles_nil;
    }

    list->status = CAIRO_STATUS_SUCCESS;
    list->rectangles = rectangles;
    list->num_rectangles = n_boxes;
    return list;
}
/* This special-case filler supports only a path that describes a
 * device-axis aligned rectangle. It exists to avoid the overhead of
 * the general tessellator when drawing very common rectangles.
 *
 * If the path described anything but a device-axis aligned rectangle,
 * this function will abort.
 */
cairo_region_t *
_cairo_path_fixed_fill_rectilinear_to_region (const cairo_path_fixed_t	*path,
					      cairo_fill_rule_t	 fill_rule,
					      const cairo_rectangle_int_t *extents)
{
    cairo_rectangle_int_t rectangle_stack[CAIRO_STACK_ARRAY_LENGTH (cairo_rectangle_int_t)];
    cairo_box_t box;
    cairo_region_t *region = NULL;

    assert (path->maybe_fill_region);
    assert (! path->is_empty_fill);

    if (_cairo_path_fixed_is_box (path, &box)) {
	rectangle_stack[0].x = _cairo_fixed_integer_part (box.p1.x);
	rectangle_stack[0].y = _cairo_fixed_integer_part (box.p1.y);
	rectangle_stack[0].width = _cairo_fixed_integer_part (box.p2.x) -
	                            rectangle_stack[0].x;
	rectangle_stack[0].height = _cairo_fixed_integer_part (box.p2.y) -
	                            rectangle_stack[0].y;
	if (! _cairo_rectangle_intersect (&rectangle_stack[0], extents))
	    region = cairo_region_create ();
	else
	    region = cairo_region_create_rectangle (&rectangle_stack[0]);
    } else if (fill_rule == CAIRO_FILL_RULE_WINDING) {
	cairo_rectangle_int_t *rects = rectangle_stack;
	cairo_path_fixed_iter_t iter;
	int last_cw = -1;
	int size = ARRAY_LENGTH (rectangle_stack);
	int count = 0;

	/* Support a series of rectangles as can be expected to describe a
	 * GdkRegion clip region during exposes.
	 */
	_cairo_path_fixed_iter_init (&iter, path);
	while (_cairo_path_fixed_iter_is_fill_box (&iter, &box)) {
	    int cw = 0;

	    if (box.p1.x > box.p2.x) {
		cairo_fixed_t t;

		t = box.p1.x;
		box.p1.x = box.p2.x;
		box.p2.x = t;

		cw = ! cw;
	    }

	    if (box.p1.y > box.p2.y) {
		cairo_fixed_t t;

		t = box.p1.y;
		box.p1.y = box.p2.y;
		box.p2.y = t;

		cw = ! cw;
	    }

	    if (last_cw < 0)
		last_cw = cw;
	    else if (last_cw != cw)
		goto TESSELLATE;

	    if (count == size) {
		cairo_rectangle_int_t *new_rects;

		size *= 4;
		if (rects == rectangle_stack) {
		    new_rects = _cairo_malloc_ab (size,
						  sizeof (cairo_rectangle_int_t));
		    if (unlikely (new_rects == NULL)) {
			/* XXX _cairo_region_nil */
			break;
		    }
		    memcpy (new_rects, rects, sizeof (rectangle_stack));
		} else {
		    new_rects = _cairo_realloc_ab (rects, size,
						   sizeof (cairo_rectangle_int_t));
		    if (unlikely (new_rects == NULL)) {
			/* XXX _cairo_region_nil */
			break;
		    }
		}
		rects = new_rects;
	    }

	    rects[count].x = _cairo_fixed_integer_part (box.p1.x);
	    rects[count].y = _cairo_fixed_integer_part (box.p1.y);
	    rects[count].width = _cairo_fixed_integer_part (box.p2.x) - rects[count].x;
	    rects[count].height = _cairo_fixed_integer_part (box.p2.y) - rects[count].y;
	    if (_cairo_rectangle_intersect (&rects[count], extents))
		count++;
	}

	if (_cairo_path_fixed_iter_at_end (&iter))
	    region = cairo_region_create_rectangles (rects, count);

TESSELLATE:
	if (rects != rectangle_stack)
	    free (rects);
    }

    if (region == NULL) {
	/* Hmm, complex polygon */
	region = _cairo_path_fixed_fill_rectilinear_tessellate_to_region (path,
									  fill_rule,
									  extents);


    }

    return region;
}
예제 #29
0
static cairo_status_t
_cairo_scaled_font_subsets_foreach_internal (cairo_scaled_font_subsets_t              *font_subsets,
                                             cairo_scaled_font_subset_callback_func_t  font_subset_callback,
                                             void				      *closure,
					     cairo_subsets_foreach_type_t	       type)
{
    cairo_sub_font_collection_t collection;
    cairo_sub_font_t *sub_font;
    cairo_bool_t is_scaled, is_user;

    is_scaled = FALSE;
    is_user = FALSE;

    if (type == CAIRO_SUBSETS_FOREACH_USER)
	is_user = TRUE;

    if (type == CAIRO_SUBSETS_FOREACH_SCALED ||
	type == CAIRO_SUBSETS_FOREACH_USER)
    {
	is_scaled = TRUE;
    }

    if (is_scaled)
        collection.glyphs_size = font_subsets->max_glyphs_per_scaled_subset_used;
    else
        collection.glyphs_size = font_subsets->max_glyphs_per_unscaled_subset_used;

    if (! collection.glyphs_size)
	return CAIRO_STATUS_SUCCESS;

    collection.glyphs = _cairo_malloc_ab (collection.glyphs_size, sizeof(unsigned long));
    collection.utf8 = _cairo_malloc_ab (collection.glyphs_size, sizeof(char *));
    collection.to_latin_char = _cairo_malloc_ab (collection.glyphs_size, sizeof(int));
    collection.latin_to_subset_glyph_index = _cairo_malloc_ab (256, sizeof(unsigned long));
    if (unlikely (collection.glyphs == NULL ||
		  collection.utf8 == NULL ||
		  collection.to_latin_char == NULL ||
		  collection.latin_to_subset_glyph_index == NULL)) {
	free (collection.glyphs);
	free (collection.utf8);
	free (collection.to_latin_char);
	free (collection.latin_to_subset_glyph_index);

	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
    }

    collection.font_subset_callback = font_subset_callback;
    collection.font_subset_callback_closure = closure;
    collection.status = CAIRO_STATUS_SUCCESS;

    if (is_scaled)
	sub_font = font_subsets->scaled_sub_fonts_list;
    else
	sub_font = font_subsets->unscaled_sub_fonts_list;

    while (sub_font) {
	if (sub_font->is_user == is_user)
	    _cairo_sub_font_collect (sub_font, &collection);

	sub_font = sub_font->next;
    }
    free (collection.utf8);
    free (collection.glyphs);
    free (collection.to_latin_char);
    free (collection.latin_to_subset_glyph_index);

    return collection.status;
}
예제 #30
0
cairo_int_status_t
_cairo_win32_surface_emit_glyphs (cairo_win32_surface_t *dst,
                                  const cairo_pattern_t *source,
                                  cairo_glyph_t	 *glyphs,
                                  int			  num_glyphs,
                                  cairo_scaled_font_t	 *scaled_font,
                                  cairo_bool_t		  glyph_indexing)
{
#if CAIRO_HAS_WIN32_FONT
    WORD glyph_buf_stack[STACK_GLYPH_SIZE];
    WORD *glyph_buf = glyph_buf_stack;
    int dxy_buf_stack[2 * STACK_GLYPH_SIZE];
    int *dxy_buf = dxy_buf_stack;

    BOOL win_result = 0;
    int i, j;

    cairo_solid_pattern_t *solid_pattern;
    COLORREF color;

    cairo_matrix_t device_to_logical;

    int start_x, start_y;
    double user_x, user_y;
    int logical_x, logical_y;
    unsigned int glyph_index_option;

    /* We can only handle win32 fonts */
    assert (cairo_scaled_font_get_type (scaled_font) == CAIRO_FONT_TYPE_WIN32);

    /* We can only handle opaque solid color sources and destinations */
    assert (_cairo_pattern_is_opaque_solid(source));
    assert (dst->format == CAIRO_FORMAT_RGB24);

    solid_pattern = (cairo_solid_pattern_t *)source;
    color = RGB(((int)solid_pattern->color.red_short) >> 8,
                ((int)solid_pattern->color.green_short) >> 8,
                ((int)solid_pattern->color.blue_short) >> 8);

    cairo_win32_scaled_font_get_device_to_logical(scaled_font, &device_to_logical);

    SaveDC(dst->dc);

    cairo_win32_scaled_font_select_font(scaled_font, dst->dc);
    SetTextColor(dst->dc, color);
    SetTextAlign(dst->dc, TA_BASELINE | TA_LEFT);
    SetBkMode(dst->dc, TRANSPARENT);

    if (num_glyphs > STACK_GLYPH_SIZE) {
        glyph_buf = (WORD *) _cairo_malloc_ab (num_glyphs, sizeof(WORD));
        dxy_buf = (int *) _cairo_malloc_abc (num_glyphs, sizeof(int), 2);
    }

    /* It is vital that dx values for dxy_buf are calculated from the delta of
     * _logical_ x coordinates (not user x coordinates) or else the sum of all
     * previous dx values may start to diverge from the current glyph's x
     * coordinate due to accumulated rounding error. As a result strings could
     * be painted shorter or longer than expected. */

    user_x = glyphs[0].x;
    user_y = glyphs[0].y;

    cairo_matrix_transform_point(&device_to_logical,
                                 &user_x, &user_y);

    logical_x = _cairo_lround (user_x);
    logical_y = _cairo_lround (user_y);

    start_x = logical_x;
    start_y = logical_y;

    for (i = 0, j = 0; i < num_glyphs; ++i, j = 2 * i) {
        glyph_buf[i] = (WORD) glyphs[i].index;
        if (i == num_glyphs - 1) {
            dxy_buf[j] = 0;
            dxy_buf[j+1] = 0;
        } else {
            double next_user_x = glyphs[i+1].x;
            double next_user_y = glyphs[i+1].y;
            int next_logical_x, next_logical_y;

            cairo_matrix_transform_point(&device_to_logical,
                                         &next_user_x, &next_user_y);

            next_logical_x = _cairo_lround (next_user_x);
            next_logical_y = _cairo_lround (next_user_y);

            dxy_buf[j] = _cairo_lround (next_logical_x - logical_x);
            dxy_buf[j+1] = _cairo_lround (next_logical_y - logical_y);

            logical_x = next_logical_x;
            logical_y = next_logical_y;
        }
    }

    if (glyph_indexing)
        glyph_index_option = ETO_GLYPH_INDEX;
    else
        glyph_index_option = 0;

    win_result = ExtTextOutW(dst->dc,
                             start_x,
                             start_y,
                             glyph_index_option | ETO_PDY,
                             NULL,
                             glyph_buf,
                             num_glyphs,
                             dxy_buf);
    if (!win_result) {
        _cairo_win32_print_gdi_error("_cairo_win32_surface_show_glyphs(ExtTextOutW failed)");
    }

    RestoreDC(dst->dc, -1);

    if (glyph_buf != glyph_buf_stack) {
        free(glyph_buf);
        free(dxy_buf);
    }
    return (win_result) ? CAIRO_STATUS_SUCCESS : CAIRO_INT_STATUS_UNSUPPORTED;
#else
    return CAIRO_INT_STATUS_UNSUPPORTED;
#endif
}