mirror of
https://gitlab.freedesktop.org/cairo/cairo.git
synced 2026-01-04 06:20:19 +01:00
Generate convex hull of pen before stroking.
This commit is contained in:
parent
a249bd717c
commit
61726a88f2
11 changed files with 534 additions and 179 deletions
|
|
@ -1,5 +1,13 @@
|
|||
2003-10-04 Carl Worth <cworth@isi.edu>
|
||||
|
||||
* src/cairo_hull.c (_cairo_hull_compute): Add cairo_hull.c to
|
||||
compute a convex hull, (using Graham scan algorithm).
|
||||
|
||||
* src/cairo_pen.c (_cairo_pen_add_points): Generate convex hull of
|
||||
pen after adding new points.
|
||||
|
||||
* src/cairoint.h: Rename pen->vertex to pen->vertices
|
||||
|
||||
* Replaced "pt" with "point" in about a zillion places.
|
||||
|
||||
* src/cairo.c (cairo_destroy): Fix to continue with destroy even
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ libcairo_la_SOURCES = \
|
|||
cairo_fixed.c \
|
||||
cairo_font.c \
|
||||
cairo_gstate.c \
|
||||
cairo_hull.c \
|
||||
cairo_matrix.c \
|
||||
cairo_path.c \
|
||||
cairo_path_bounds.c \
|
||||
|
|
|
|||
190
src/cairo-hull.c
Normal file
190
src/cairo-hull.c
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
/*
|
||||
* Copyright © 2003 USC, Information Sciences Institute
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software
|
||||
* and its documentation for any purpose is hereby granted without
|
||||
* fee, provided that the above copyright notice appear in all copies
|
||||
* and that both that copyright notice and this permission notice
|
||||
* appear in supporting documentation, and that the name of the
|
||||
* University of Southern California not be used in advertising or
|
||||
* publicity pertaining to distribution of the software without
|
||||
* specific, written prior permission. The University of Southern
|
||||
* California makes no representations about the suitability of this
|
||||
* software for any purpose. It is provided "as is" without express
|
||||
* or implied warranty.
|
||||
*
|
||||
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
|
||||
* SOUTHERN CALIFORNIA BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
||||
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* Author: Carl D. Worth <cworth@isi.edu>
|
||||
*/
|
||||
|
||||
#include "cairoint.h"
|
||||
|
||||
typedef struct cairo_hull
|
||||
{
|
||||
cairo_point_t point;
|
||||
cairo_slope_t slope;
|
||||
int discard;
|
||||
} cairo_hull_t;
|
||||
|
||||
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 = malloc (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);
|
||||
|
||||
/* 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;
|
||||
else
|
||||
hull[i].discard = 0;
|
||||
}
|
||||
|
||||
return hull;
|
||||
}
|
||||
|
||||
static int
|
||||
_cairo_hull_vertex_compare (const void *av, const void *bv)
|
||||
{
|
||||
cairo_hull_t *a = (cairo_hull_t *) av;
|
||||
cairo_hull_t *b = (cairo_hull_t *) bv;
|
||||
int ret;
|
||||
|
||||
ret = _cairo_slope_compare (&a->slope, &b->slope);
|
||||
|
||||
/* In the case of two vertices with identical slope from the
|
||||
extremal point discard the nearer point. */
|
||||
|
||||
if (ret == 0) {
|
||||
cairo_fixed_48_16_t a_dist, b_dist;
|
||||
a_dist = ((cairo_fixed_48_16_t) a->slope.dx * a->slope.dx +
|
||||
(cairo_fixed_48_16_t) a->slope.dy * a->slope.dy);
|
||||
b_dist = ((cairo_fixed_48_16_t) b->slope.dx * b->slope.dx +
|
||||
(cairo_fixed_48_16_t) b->slope.dy * b->slope.dy);
|
||||
if (a_dist < b_dist)
|
||||
a->discard = 1;
|
||||
else
|
||||
b->discard = 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
_cairo_hull_prev_valid (cairo_hull_t *hull, int num_hull, int index)
|
||||
{
|
||||
do {
|
||||
/* hull[0] is always valid, so don't test and wraparound */
|
||||
index--;
|
||||
} while (hull[index].discard);
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
static int
|
||||
_cairo_hull_next_valid (cairo_hull_t *hull, int num_hull, int index)
|
||||
{
|
||||
do {
|
||||
index = (index + 1) % num_hull;
|
||||
} while (hull[index].discard);
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_hull_eliminate_concave (cairo_hull_t *hull, int num_hull)
|
||||
{
|
||||
int i, j, k;
|
||||
cairo_slope_t slope_ij, slope_jk;
|
||||
|
||||
i = 0;
|
||||
j = _cairo_hull_next_valid (hull, num_hull, i);
|
||||
k = _cairo_hull_next_valid (hull, num_hull, j);
|
||||
|
||||
do {
|
||||
_cairo_slope_init (&slope_ij, &hull[i].point, &hull[j].point);
|
||||
_cairo_slope_init (&slope_jk, &hull[j].point, &hull[k].point);
|
||||
|
||||
/* Is the angle formed by ij and jk concave? */
|
||||
if (_cairo_slope_compare (&slope_ij, &slope_jk) >= 0) {
|
||||
if (i == k)
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
hull[j].discard = 1;
|
||||
j = i;
|
||||
i = _cairo_hull_prev_valid (hull, num_hull, j);
|
||||
} else {
|
||||
i = j;
|
||||
j = k;
|
||||
k = _cairo_hull_next_valid (hull, num_hull, j);
|
||||
}
|
||||
} while (j != 0);
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_hull_to_pen (cairo_hull_t *hull, cairo_pen_vertex_t *vertices, int *num_vertices)
|
||||
{
|
||||
int i, j = 0;
|
||||
|
||||
for (i = 0; i < *num_vertices; i++) {
|
||||
if (hull[i].discard)
|
||||
continue;
|
||||
vertices[j++].point = hull[i].point;
|
||||
}
|
||||
|
||||
*num_vertices = j;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* Given a set of vertices, compute the convex hull using the Graham
|
||||
scan algorithm. */
|
||||
cairo_status_t
|
||||
_cairo_hull_compute (cairo_pen_vertex_t *vertices, int *num_vertices)
|
||||
{
|
||||
cairo_hull_t *hull;
|
||||
int num_hull = *num_vertices;
|
||||
|
||||
hull = _cairo_hull_create (vertices, num_hull);
|
||||
if (hull == NULL)
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
|
||||
qsort (hull + 1, num_hull - 1,
|
||||
sizeof (cairo_hull_t), _cairo_hull_vertex_compare);
|
||||
|
||||
_cairo_hull_eliminate_concave (hull, num_hull);
|
||||
|
||||
_cairo_hull_to_pen (hull, vertices, num_vertices);
|
||||
|
||||
free (hull);
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
|
@ -189,7 +189,7 @@ _cairo_stroker_join (cairo_stroker_t *stroker, cairo_stroke_face_t *in, cairo_st
|
|||
tri[1] = *inpt;
|
||||
while (i != stop) {
|
||||
tri[2] = in->point;
|
||||
_translate_point (&tri[2], &pen->vertex[i].point);
|
||||
_translate_point (&tri[2], &pen->vertices[i].point);
|
||||
_cairo_traps_tessellate_triangle (stroker->traps, tri);
|
||||
tri[1] = tri[2];
|
||||
i += step;
|
||||
|
|
@ -337,7 +337,7 @@ _cairo_stroker_cap (cairo_stroker_t *stroker, cairo_stroke_face_t *f)
|
|||
tri[1] = f->cw;
|
||||
for (i=start; i != stop; i = (i+1) % pen->num_vertices) {
|
||||
tri[2] = f->point;
|
||||
_translate_point (&tri[2], &pen->vertex[i].point);
|
||||
_translate_point (&tri[2], &pen->vertices[i].point);
|
||||
_cairo_traps_tessellate_triangle (stroker->traps, tri);
|
||||
tri[1] = tri[2];
|
||||
}
|
||||
|
|
|
|||
115
src/cairo-pen.c
115
src/cairo-pen.c
|
|
@ -33,9 +33,6 @@ _cairo_pen_vertices_needed (double radius, double tolerance, double expansion);
|
|||
static void
|
||||
_cairo_pen_compute_slopes (cairo_pen_t *pen);
|
||||
|
||||
static int
|
||||
_pen_vertex_compare (const void *av, const void *bv);
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_pen_stroke_spline_half (cairo_pen_t *pen, cairo_spline_t *spline, cairo_direction_t dir, cairo_polygon_t *polygon);
|
||||
|
||||
|
|
@ -44,7 +41,7 @@ _cairo_pen_init_empty (cairo_pen_t *pen)
|
|||
{
|
||||
pen->radius = 0;
|
||||
pen->tolerance = 0;
|
||||
pen->vertex = NULL;
|
||||
pen->vertices = NULL;
|
||||
pen->num_vertices = 0;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
|
|
@ -88,8 +85,8 @@ _cairo_pen_init (cairo_pen_t *pen, double radius, cairo_gstate_t *gstate)
|
|||
if (pen->num_vertices % 2)
|
||||
pen->num_vertices++;
|
||||
|
||||
pen->vertex = malloc (pen->num_vertices * sizeof (cairo_pen_vertex_t));
|
||||
if (pen->vertex == NULL) {
|
||||
pen->vertices = malloc (pen->num_vertices * sizeof (cairo_pen_vertex_t));
|
||||
if (pen->vertices == NULL) {
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
|
|
@ -103,7 +100,7 @@ _cairo_pen_init (cairo_pen_t *pen, double radius, cairo_gstate_t *gstate)
|
|||
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->vertex[i];
|
||||
cairo_pen_vertex_t *v = &pen->vertices[i];
|
||||
cairo_matrix_transform_distance (&gstate->ctm, &dx, &dy);
|
||||
v->point.x = _cairo_fixed_from_double (dx);
|
||||
v->point.y = _cairo_fixed_from_double (dy);
|
||||
|
|
@ -117,7 +114,7 @@ _cairo_pen_init (cairo_pen_t *pen, double radius, cairo_gstate_t *gstate)
|
|||
void
|
||||
_cairo_pen_fini (cairo_pen_t *pen)
|
||||
{
|
||||
free (pen->vertex);
|
||||
free (pen->vertices);
|
||||
_cairo_pen_init_empty (pen);
|
||||
}
|
||||
|
||||
|
|
@ -127,11 +124,11 @@ _cairo_pen_init_copy (cairo_pen_t *pen, cairo_pen_t *other)
|
|||
*pen = *other;
|
||||
|
||||
if (pen->num_vertices) {
|
||||
pen->vertex = malloc (pen->num_vertices * sizeof (cairo_pen_vertex_t));
|
||||
if (pen->vertex == NULL) {
|
||||
pen->vertices = malloc (pen->num_vertices * sizeof (cairo_pen_vertex_t));
|
||||
if (pen->vertices == NULL) {
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
}
|
||||
memcpy (pen->vertex, other->vertex, pen->num_vertices * sizeof (cairo_pen_vertex_t));
|
||||
memcpy (pen->vertices, other->vertices, pen->num_vertices * sizeof (cairo_pen_vertex_t));
|
||||
}
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
|
|
@ -140,37 +137,23 @@ _cairo_pen_init_copy (cairo_pen_t *pen, cairo_pen_t *other)
|
|||
cairo_status_t
|
||||
_cairo_pen_add_points (cairo_pen_t *pen, cairo_point_t *point, int num_points)
|
||||
{
|
||||
cairo_pen_vertex_t *vertices;
|
||||
int num_vertices;
|
||||
int i;
|
||||
cairo_pen_vertex_t *v, *v_next, *new_vertex;
|
||||
|
||||
pen->num_vertices += num_points;
|
||||
new_vertex = realloc (pen->vertex, pen->num_vertices * sizeof (cairo_pen_vertex_t));
|
||||
if (new_vertex == NULL) {
|
||||
pen->num_vertices -= num_points;
|
||||
num_vertices = pen->num_vertices + num_points;
|
||||
vertices = realloc (pen->vertices, num_vertices * sizeof (cairo_pen_vertex_t));
|
||||
if (vertices == NULL)
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
}
|
||||
pen->vertex = new_vertex;
|
||||
|
||||
pen->vertices = vertices;
|
||||
pen->num_vertices = num_vertices;
|
||||
|
||||
/* initialize new vertices */
|
||||
for (i=0; i < num_points; i++) {
|
||||
v = &pen->vertex[pen->num_vertices-(i+1)];
|
||||
v->point = point[i];
|
||||
}
|
||||
for (i=0; i < num_points; i++)
|
||||
pen->vertices[pen->num_vertices-num_points+i].point = point[i];
|
||||
|
||||
qsort (pen->vertex, pen->num_vertices, sizeof (cairo_pen_vertex_t), _pen_vertex_compare);
|
||||
|
||||
/* eliminate any duplicate vertices */
|
||||
for (i=0; i < pen->num_vertices; i++ ) {
|
||||
v = &pen->vertex[i];
|
||||
v_next = (i < pen->num_vertices - 1) ? &pen->vertex[i+1] : &pen->vertex[0];
|
||||
if (_pen_vertex_compare (v, v_next) == 0) {
|
||||
pen->num_vertices--;
|
||||
memmove (&pen->vertex[i], &pen->vertex[i+1],
|
||||
(pen->num_vertices - i) * sizeof (cairo_pen_vertex_t));
|
||||
/* There may be more of the same duplicate, check again */
|
||||
i--;
|
||||
}
|
||||
}
|
||||
_cairo_hull_compute (pen->vertices, &pen->num_vertices);
|
||||
|
||||
_cairo_pen_compute_slopes (pen);
|
||||
|
||||
|
|
@ -199,53 +182,15 @@ _cairo_pen_compute_slopes (cairo_pen_t *pen)
|
|||
for (i=0, i_prev = pen->num_vertices - 1;
|
||||
i < pen->num_vertices;
|
||||
i_prev = i++) {
|
||||
prev = &pen->vertex[i_prev];
|
||||
v = &pen->vertex[i];
|
||||
next = &pen->vertex[(i + 1) % pen->num_vertices];
|
||||
prev = &pen->vertices[i_prev];
|
||||
v = &pen->vertices[i];
|
||||
next = &pen->vertices[(i + 1) % pen->num_vertices];
|
||||
|
||||
_cairo_slope_init (&v->slope_cw, &prev->point, &v->point);
|
||||
_cairo_slope_init (&v->slope_ccw, &v->point, &next->point);
|
||||
}
|
||||
}
|
||||
|
||||
/* Is a further clockwise from (1,0) than b?
|
||||
*
|
||||
* There are a two special cases to consider:
|
||||
* 1) a and b are not in the same half plane.
|
||||
* 2) both a and b are on the X axis
|
||||
* After that, the computation is a simple slope comparison.
|
||||
*/
|
||||
static int
|
||||
_pen_vertex_compare (const void *av, const void *bv)
|
||||
{
|
||||
const cairo_pen_vertex_t *a = av;
|
||||
const cairo_pen_vertex_t *b = bv;
|
||||
cairo_fixed_48_16_t diff;
|
||||
|
||||
int a_above = a->point.y >= 0;
|
||||
int b_above = b->point.y >= 0;
|
||||
|
||||
if (a_above != b_above)
|
||||
return b_above - a_above;
|
||||
|
||||
if (a->point.y == 0 && b->point.y == 0) {
|
||||
int a_right = a->point.x >= 0;
|
||||
int b_right = b->point.x >= 0;
|
||||
|
||||
if (a_right != b_right)
|
||||
return b_right - a_right;
|
||||
}
|
||||
|
||||
diff = ((cairo_fixed_48_16_t) a->point.y * (cairo_fixed_48_16_t) b->point.x
|
||||
- (cairo_fixed_48_16_t) b->point.y * (cairo_fixed_48_16_t) a->point.x);
|
||||
|
||||
if (diff > 0)
|
||||
return 1;
|
||||
if (diff < 0)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Find active pen vertex for clockwise edge of stroke at the given slope.
|
||||
*
|
||||
* NOTE: The behavior of this function is sensitive to the sense of
|
||||
|
|
@ -264,8 +209,8 @@ _cairo_pen_find_active_cw_vertex_index (cairo_pen_t *pen,
|
|||
int i;
|
||||
|
||||
for (i=0; i < pen->num_vertices; i++) {
|
||||
if (_cairo_slope_clockwise (slope, &pen->vertex[i].slope_ccw)
|
||||
&& _cairo_slope_counter_clockwise (slope, &pen->vertex[i].slope_cw))
|
||||
if (_cairo_slope_clockwise (slope, &pen->vertices[i].slope_ccw)
|
||||
&& _cairo_slope_counter_clockwise (slope, &pen->vertices[i].slope_cw))
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -292,8 +237,8 @@ _cairo_pen_find_active_ccw_vertex_index (cairo_pen_t *pen,
|
|||
slope_reverse.dy = -slope_reverse.dy;
|
||||
|
||||
for (i=pen->num_vertices-1; i >= 0; i--) {
|
||||
if (_cairo_slope_counter_clockwise (&pen->vertex[i].slope_ccw, &slope_reverse)
|
||||
&& _cairo_slope_clockwise (&pen->vertex[i].slope_cw, &slope_reverse))
|
||||
if (_cairo_slope_counter_clockwise (&pen->vertices[i].slope_ccw, &slope_reverse)
|
||||
&& _cairo_slope_clockwise (&pen->vertices[i].slope_cw, &slope_reverse))
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -339,8 +284,8 @@ _cairo_pen_stroke_spline_half (cairo_pen_t *pen,
|
|||
|
||||
i = start;
|
||||
while (i != stop) {
|
||||
hull_point.x = point[i].x + pen->vertex[active].point.x;
|
||||
hull_point.y = point[i].y + pen->vertex[active].point.y;
|
||||
hull_point.x = point[i].x + pen->vertices[active].point.x;
|
||||
hull_point.y = point[i].y + pen->vertices[active].point.y;
|
||||
status = _cairo_polygon_add_point (polygon, &hull_point);
|
||||
if (status)
|
||||
return status;
|
||||
|
|
@ -349,10 +294,10 @@ _cairo_pen_stroke_spline_half (cairo_pen_t *pen,
|
|||
slope = final_slope;
|
||||
else
|
||||
_cairo_slope_init (&slope, &point[i], &point[i+step]);
|
||||
if (_cairo_slope_counter_clockwise (&slope, &pen->vertex[active].slope_ccw)) {
|
||||
if (_cairo_slope_counter_clockwise (&slope, &pen->vertices[active].slope_ccw)) {
|
||||
if (++active == pen->num_vertices)
|
||||
active = 0;
|
||||
} else if (_cairo_slope_clockwise (&slope, &pen->vertex[active].slope_cw)) {
|
||||
} else if (_cairo_slope_clockwise (&slope, &pen->vertices[active].slope_cw)) {
|
||||
if (--active == -1)
|
||||
active = pen->num_vertices - 1;
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -34,6 +34,43 @@ _cairo_slope_init (cairo_slope_t *slope, cairo_point_t *a, cairo_point_t *b)
|
|||
slope->dy = b->y - a->y;
|
||||
}
|
||||
|
||||
/* Compare two slopes. Slope angles begin at 0 in the direction of the
|
||||
positive X axis and increase in the direction of the positive Y
|
||||
axis.
|
||||
|
||||
WARNING: This function only gives correct results if the angular
|
||||
difference between a and b is less than PI.
|
||||
|
||||
< 0 => a less positive than b
|
||||
== 0 => a equal to be
|
||||
> 0 => a more positive than b
|
||||
*/
|
||||
int
|
||||
_cairo_slope_compare (cairo_slope_t *a, cairo_slope_t *b)
|
||||
{
|
||||
cairo_fixed_48_16_t diff;
|
||||
|
||||
diff = ((cairo_fixed_48_16_t) a->dy * (cairo_fixed_48_16_t) b->dx
|
||||
- (cairo_fixed_48_16_t) b->dy * (cairo_fixed_48_16_t) a->dx);
|
||||
|
||||
if (diff > 0)
|
||||
return 1;
|
||||
if (diff < 0)
|
||||
return -1;
|
||||
|
||||
if (a->dx == 0 && a->dy == 0)
|
||||
return 1;
|
||||
if (b->dx == 0 && b->dy ==0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* XXX: It might be cleaner to move away from usage of
|
||||
_cairo_slope_clockwise/_cairo_slope_counter_clockwise in favor of
|
||||
directly using _cairo_slope_compare.
|
||||
*/
|
||||
|
||||
/* Is a clockwise of b?
|
||||
*
|
||||
* NOTE: The strict equality here is not significant in and of itself,
|
||||
|
|
@ -43,8 +80,7 @@ _cairo_slope_init (cairo_slope_t *slope, cairo_point_t *a, cairo_point_t *b)
|
|||
int
|
||||
_cairo_slope_clockwise (cairo_slope_t *a, cairo_slope_t *b)
|
||||
{
|
||||
return ((cairo_fixed_48_16_t) b->dy * (cairo_fixed_48_16_t) a->dx
|
||||
> (cairo_fixed_48_16_t) a->dy * (cairo_fixed_48_16_t) b->dx);
|
||||
return _cairo_slope_compare (a, b) < 0;
|
||||
}
|
||||
|
||||
int
|
||||
|
|
|
|||
190
src/cairo_hull.c
Normal file
190
src/cairo_hull.c
Normal file
|
|
@ -0,0 +1,190 @@
|
|||
/*
|
||||
* Copyright © 2003 USC, Information Sciences Institute
|
||||
*
|
||||
* Permission to use, copy, modify, distribute, and sell this software
|
||||
* and its documentation for any purpose is hereby granted without
|
||||
* fee, provided that the above copyright notice appear in all copies
|
||||
* and that both that copyright notice and this permission notice
|
||||
* appear in supporting documentation, and that the name of the
|
||||
* University of Southern California not be used in advertising or
|
||||
* publicity pertaining to distribution of the software without
|
||||
* specific, written prior permission. The University of Southern
|
||||
* California makes no representations about the suitability of this
|
||||
* software for any purpose. It is provided "as is" without express
|
||||
* or implied warranty.
|
||||
*
|
||||
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DISCLAIMS ALL WARRANTIES WITH
|
||||
* REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL THE UNIVERSITY OF
|
||||
* SOUTHERN CALIFORNIA BE LIABLE FOR ANY SPECIAL, INDIRECT OR
|
||||
* CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
|
||||
* OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
|
||||
* NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
|
||||
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*
|
||||
* Author: Carl D. Worth <cworth@isi.edu>
|
||||
*/
|
||||
|
||||
#include "cairoint.h"
|
||||
|
||||
typedef struct cairo_hull
|
||||
{
|
||||
cairo_point_t point;
|
||||
cairo_slope_t slope;
|
||||
int discard;
|
||||
} cairo_hull_t;
|
||||
|
||||
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 = malloc (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);
|
||||
|
||||
/* 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;
|
||||
else
|
||||
hull[i].discard = 0;
|
||||
}
|
||||
|
||||
return hull;
|
||||
}
|
||||
|
||||
static int
|
||||
_cairo_hull_vertex_compare (const void *av, const void *bv)
|
||||
{
|
||||
cairo_hull_t *a = (cairo_hull_t *) av;
|
||||
cairo_hull_t *b = (cairo_hull_t *) bv;
|
||||
int ret;
|
||||
|
||||
ret = _cairo_slope_compare (&a->slope, &b->slope);
|
||||
|
||||
/* In the case of two vertices with identical slope from the
|
||||
extremal point discard the nearer point. */
|
||||
|
||||
if (ret == 0) {
|
||||
cairo_fixed_48_16_t a_dist, b_dist;
|
||||
a_dist = ((cairo_fixed_48_16_t) a->slope.dx * a->slope.dx +
|
||||
(cairo_fixed_48_16_t) a->slope.dy * a->slope.dy);
|
||||
b_dist = ((cairo_fixed_48_16_t) b->slope.dx * b->slope.dx +
|
||||
(cairo_fixed_48_16_t) b->slope.dy * b->slope.dy);
|
||||
if (a_dist < b_dist)
|
||||
a->discard = 1;
|
||||
else
|
||||
b->discard = 1;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
_cairo_hull_prev_valid (cairo_hull_t *hull, int num_hull, int index)
|
||||
{
|
||||
do {
|
||||
/* hull[0] is always valid, so don't test and wraparound */
|
||||
index--;
|
||||
} while (hull[index].discard);
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
static int
|
||||
_cairo_hull_next_valid (cairo_hull_t *hull, int num_hull, int index)
|
||||
{
|
||||
do {
|
||||
index = (index + 1) % num_hull;
|
||||
} while (hull[index].discard);
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_hull_eliminate_concave (cairo_hull_t *hull, int num_hull)
|
||||
{
|
||||
int i, j, k;
|
||||
cairo_slope_t slope_ij, slope_jk;
|
||||
|
||||
i = 0;
|
||||
j = _cairo_hull_next_valid (hull, num_hull, i);
|
||||
k = _cairo_hull_next_valid (hull, num_hull, j);
|
||||
|
||||
do {
|
||||
_cairo_slope_init (&slope_ij, &hull[i].point, &hull[j].point);
|
||||
_cairo_slope_init (&slope_jk, &hull[j].point, &hull[k].point);
|
||||
|
||||
/* Is the angle formed by ij and jk concave? */
|
||||
if (_cairo_slope_compare (&slope_ij, &slope_jk) >= 0) {
|
||||
if (i == k)
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
hull[j].discard = 1;
|
||||
j = i;
|
||||
i = _cairo_hull_prev_valid (hull, num_hull, j);
|
||||
} else {
|
||||
i = j;
|
||||
j = k;
|
||||
k = _cairo_hull_next_valid (hull, num_hull, j);
|
||||
}
|
||||
} while (j != 0);
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_hull_to_pen (cairo_hull_t *hull, cairo_pen_vertex_t *vertices, int *num_vertices)
|
||||
{
|
||||
int i, j = 0;
|
||||
|
||||
for (i = 0; i < *num_vertices; i++) {
|
||||
if (hull[i].discard)
|
||||
continue;
|
||||
vertices[j++].point = hull[i].point;
|
||||
}
|
||||
|
||||
*num_vertices = j;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* Given a set of vertices, compute the convex hull using the Graham
|
||||
scan algorithm. */
|
||||
cairo_status_t
|
||||
_cairo_hull_compute (cairo_pen_vertex_t *vertices, int *num_vertices)
|
||||
{
|
||||
cairo_hull_t *hull;
|
||||
int num_hull = *num_vertices;
|
||||
|
||||
hull = _cairo_hull_create (vertices, num_hull);
|
||||
if (hull == NULL)
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
|
||||
qsort (hull + 1, num_hull - 1,
|
||||
sizeof (cairo_hull_t), _cairo_hull_vertex_compare);
|
||||
|
||||
_cairo_hull_eliminate_concave (hull, num_hull);
|
||||
|
||||
_cairo_hull_to_pen (hull, vertices, num_vertices);
|
||||
|
||||
free (hull);
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
}
|
||||
|
|
@ -189,7 +189,7 @@ _cairo_stroker_join (cairo_stroker_t *stroker, cairo_stroke_face_t *in, cairo_st
|
|||
tri[1] = *inpt;
|
||||
while (i != stop) {
|
||||
tri[2] = in->point;
|
||||
_translate_point (&tri[2], &pen->vertex[i].point);
|
||||
_translate_point (&tri[2], &pen->vertices[i].point);
|
||||
_cairo_traps_tessellate_triangle (stroker->traps, tri);
|
||||
tri[1] = tri[2];
|
||||
i += step;
|
||||
|
|
@ -337,7 +337,7 @@ _cairo_stroker_cap (cairo_stroker_t *stroker, cairo_stroke_face_t *f)
|
|||
tri[1] = f->cw;
|
||||
for (i=start; i != stop; i = (i+1) % pen->num_vertices) {
|
||||
tri[2] = f->point;
|
||||
_translate_point (&tri[2], &pen->vertex[i].point);
|
||||
_translate_point (&tri[2], &pen->vertices[i].point);
|
||||
_cairo_traps_tessellate_triangle (stroker->traps, tri);
|
||||
tri[1] = tri[2];
|
||||
}
|
||||
|
|
|
|||
115
src/cairo_pen.c
115
src/cairo_pen.c
|
|
@ -33,9 +33,6 @@ _cairo_pen_vertices_needed (double radius, double tolerance, double expansion);
|
|||
static void
|
||||
_cairo_pen_compute_slopes (cairo_pen_t *pen);
|
||||
|
||||
static int
|
||||
_pen_vertex_compare (const void *av, const void *bv);
|
||||
|
||||
static cairo_status_t
|
||||
_cairo_pen_stroke_spline_half (cairo_pen_t *pen, cairo_spline_t *spline, cairo_direction_t dir, cairo_polygon_t *polygon);
|
||||
|
||||
|
|
@ -44,7 +41,7 @@ _cairo_pen_init_empty (cairo_pen_t *pen)
|
|||
{
|
||||
pen->radius = 0;
|
||||
pen->tolerance = 0;
|
||||
pen->vertex = NULL;
|
||||
pen->vertices = NULL;
|
||||
pen->num_vertices = 0;
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
|
|
@ -88,8 +85,8 @@ _cairo_pen_init (cairo_pen_t *pen, double radius, cairo_gstate_t *gstate)
|
|||
if (pen->num_vertices % 2)
|
||||
pen->num_vertices++;
|
||||
|
||||
pen->vertex = malloc (pen->num_vertices * sizeof (cairo_pen_vertex_t));
|
||||
if (pen->vertex == NULL) {
|
||||
pen->vertices = malloc (pen->num_vertices * sizeof (cairo_pen_vertex_t));
|
||||
if (pen->vertices == NULL) {
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
|
|
@ -103,7 +100,7 @@ _cairo_pen_init (cairo_pen_t *pen, double radius, cairo_gstate_t *gstate)
|
|||
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->vertex[i];
|
||||
cairo_pen_vertex_t *v = &pen->vertices[i];
|
||||
cairo_matrix_transform_distance (&gstate->ctm, &dx, &dy);
|
||||
v->point.x = _cairo_fixed_from_double (dx);
|
||||
v->point.y = _cairo_fixed_from_double (dy);
|
||||
|
|
@ -117,7 +114,7 @@ _cairo_pen_init (cairo_pen_t *pen, double radius, cairo_gstate_t *gstate)
|
|||
void
|
||||
_cairo_pen_fini (cairo_pen_t *pen)
|
||||
{
|
||||
free (pen->vertex);
|
||||
free (pen->vertices);
|
||||
_cairo_pen_init_empty (pen);
|
||||
}
|
||||
|
||||
|
|
@ -127,11 +124,11 @@ _cairo_pen_init_copy (cairo_pen_t *pen, cairo_pen_t *other)
|
|||
*pen = *other;
|
||||
|
||||
if (pen->num_vertices) {
|
||||
pen->vertex = malloc (pen->num_vertices * sizeof (cairo_pen_vertex_t));
|
||||
if (pen->vertex == NULL) {
|
||||
pen->vertices = malloc (pen->num_vertices * sizeof (cairo_pen_vertex_t));
|
||||
if (pen->vertices == NULL) {
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
}
|
||||
memcpy (pen->vertex, other->vertex, pen->num_vertices * sizeof (cairo_pen_vertex_t));
|
||||
memcpy (pen->vertices, other->vertices, pen->num_vertices * sizeof (cairo_pen_vertex_t));
|
||||
}
|
||||
|
||||
return CAIRO_STATUS_SUCCESS;
|
||||
|
|
@ -140,37 +137,23 @@ _cairo_pen_init_copy (cairo_pen_t *pen, cairo_pen_t *other)
|
|||
cairo_status_t
|
||||
_cairo_pen_add_points (cairo_pen_t *pen, cairo_point_t *point, int num_points)
|
||||
{
|
||||
cairo_pen_vertex_t *vertices;
|
||||
int num_vertices;
|
||||
int i;
|
||||
cairo_pen_vertex_t *v, *v_next, *new_vertex;
|
||||
|
||||
pen->num_vertices += num_points;
|
||||
new_vertex = realloc (pen->vertex, pen->num_vertices * sizeof (cairo_pen_vertex_t));
|
||||
if (new_vertex == NULL) {
|
||||
pen->num_vertices -= num_points;
|
||||
num_vertices = pen->num_vertices + num_points;
|
||||
vertices = realloc (pen->vertices, num_vertices * sizeof (cairo_pen_vertex_t));
|
||||
if (vertices == NULL)
|
||||
return CAIRO_STATUS_NO_MEMORY;
|
||||
}
|
||||
pen->vertex = new_vertex;
|
||||
|
||||
pen->vertices = vertices;
|
||||
pen->num_vertices = num_vertices;
|
||||
|
||||
/* initialize new vertices */
|
||||
for (i=0; i < num_points; i++) {
|
||||
v = &pen->vertex[pen->num_vertices-(i+1)];
|
||||
v->point = point[i];
|
||||
}
|
||||
for (i=0; i < num_points; i++)
|
||||
pen->vertices[pen->num_vertices-num_points+i].point = point[i];
|
||||
|
||||
qsort (pen->vertex, pen->num_vertices, sizeof (cairo_pen_vertex_t), _pen_vertex_compare);
|
||||
|
||||
/* eliminate any duplicate vertices */
|
||||
for (i=0; i < pen->num_vertices; i++ ) {
|
||||
v = &pen->vertex[i];
|
||||
v_next = (i < pen->num_vertices - 1) ? &pen->vertex[i+1] : &pen->vertex[0];
|
||||
if (_pen_vertex_compare (v, v_next) == 0) {
|
||||
pen->num_vertices--;
|
||||
memmove (&pen->vertex[i], &pen->vertex[i+1],
|
||||
(pen->num_vertices - i) * sizeof (cairo_pen_vertex_t));
|
||||
/* There may be more of the same duplicate, check again */
|
||||
i--;
|
||||
}
|
||||
}
|
||||
_cairo_hull_compute (pen->vertices, &pen->num_vertices);
|
||||
|
||||
_cairo_pen_compute_slopes (pen);
|
||||
|
||||
|
|
@ -199,53 +182,15 @@ _cairo_pen_compute_slopes (cairo_pen_t *pen)
|
|||
for (i=0, i_prev = pen->num_vertices - 1;
|
||||
i < pen->num_vertices;
|
||||
i_prev = i++) {
|
||||
prev = &pen->vertex[i_prev];
|
||||
v = &pen->vertex[i];
|
||||
next = &pen->vertex[(i + 1) % pen->num_vertices];
|
||||
prev = &pen->vertices[i_prev];
|
||||
v = &pen->vertices[i];
|
||||
next = &pen->vertices[(i + 1) % pen->num_vertices];
|
||||
|
||||
_cairo_slope_init (&v->slope_cw, &prev->point, &v->point);
|
||||
_cairo_slope_init (&v->slope_ccw, &v->point, &next->point);
|
||||
}
|
||||
}
|
||||
|
||||
/* Is a further clockwise from (1,0) than b?
|
||||
*
|
||||
* There are a two special cases to consider:
|
||||
* 1) a and b are not in the same half plane.
|
||||
* 2) both a and b are on the X axis
|
||||
* After that, the computation is a simple slope comparison.
|
||||
*/
|
||||
static int
|
||||
_pen_vertex_compare (const void *av, const void *bv)
|
||||
{
|
||||
const cairo_pen_vertex_t *a = av;
|
||||
const cairo_pen_vertex_t *b = bv;
|
||||
cairo_fixed_48_16_t diff;
|
||||
|
||||
int a_above = a->point.y >= 0;
|
||||
int b_above = b->point.y >= 0;
|
||||
|
||||
if (a_above != b_above)
|
||||
return b_above - a_above;
|
||||
|
||||
if (a->point.y == 0 && b->point.y == 0) {
|
||||
int a_right = a->point.x >= 0;
|
||||
int b_right = b->point.x >= 0;
|
||||
|
||||
if (a_right != b_right)
|
||||
return b_right - a_right;
|
||||
}
|
||||
|
||||
diff = ((cairo_fixed_48_16_t) a->point.y * (cairo_fixed_48_16_t) b->point.x
|
||||
- (cairo_fixed_48_16_t) b->point.y * (cairo_fixed_48_16_t) a->point.x);
|
||||
|
||||
if (diff > 0)
|
||||
return 1;
|
||||
if (diff < 0)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Find active pen vertex for clockwise edge of stroke at the given slope.
|
||||
*
|
||||
* NOTE: The behavior of this function is sensitive to the sense of
|
||||
|
|
@ -264,8 +209,8 @@ _cairo_pen_find_active_cw_vertex_index (cairo_pen_t *pen,
|
|||
int i;
|
||||
|
||||
for (i=0; i < pen->num_vertices; i++) {
|
||||
if (_cairo_slope_clockwise (slope, &pen->vertex[i].slope_ccw)
|
||||
&& _cairo_slope_counter_clockwise (slope, &pen->vertex[i].slope_cw))
|
||||
if (_cairo_slope_clockwise (slope, &pen->vertices[i].slope_ccw)
|
||||
&& _cairo_slope_counter_clockwise (slope, &pen->vertices[i].slope_cw))
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -292,8 +237,8 @@ _cairo_pen_find_active_ccw_vertex_index (cairo_pen_t *pen,
|
|||
slope_reverse.dy = -slope_reverse.dy;
|
||||
|
||||
for (i=pen->num_vertices-1; i >= 0; i--) {
|
||||
if (_cairo_slope_counter_clockwise (&pen->vertex[i].slope_ccw, &slope_reverse)
|
||||
&& _cairo_slope_clockwise (&pen->vertex[i].slope_cw, &slope_reverse))
|
||||
if (_cairo_slope_counter_clockwise (&pen->vertices[i].slope_ccw, &slope_reverse)
|
||||
&& _cairo_slope_clockwise (&pen->vertices[i].slope_cw, &slope_reverse))
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -339,8 +284,8 @@ _cairo_pen_stroke_spline_half (cairo_pen_t *pen,
|
|||
|
||||
i = start;
|
||||
while (i != stop) {
|
||||
hull_point.x = point[i].x + pen->vertex[active].point.x;
|
||||
hull_point.y = point[i].y + pen->vertex[active].point.y;
|
||||
hull_point.x = point[i].x + pen->vertices[active].point.x;
|
||||
hull_point.y = point[i].y + pen->vertices[active].point.y;
|
||||
status = _cairo_polygon_add_point (polygon, &hull_point);
|
||||
if (status)
|
||||
return status;
|
||||
|
|
@ -349,10 +294,10 @@ _cairo_pen_stroke_spline_half (cairo_pen_t *pen,
|
|||
slope = final_slope;
|
||||
else
|
||||
_cairo_slope_init (&slope, &point[i], &point[i+step]);
|
||||
if (_cairo_slope_counter_clockwise (&slope, &pen->vertex[active].slope_ccw)) {
|
||||
if (_cairo_slope_counter_clockwise (&slope, &pen->vertices[active].slope_ccw)) {
|
||||
if (++active == pen->num_vertices)
|
||||
active = 0;
|
||||
} else if (_cairo_slope_clockwise (&slope, &pen->vertex[active].slope_cw)) {
|
||||
} else if (_cairo_slope_clockwise (&slope, &pen->vertices[active].slope_cw)) {
|
||||
if (--active == -1)
|
||||
active = pen->num_vertices - 1;
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -34,6 +34,43 @@ _cairo_slope_init (cairo_slope_t *slope, cairo_point_t *a, cairo_point_t *b)
|
|||
slope->dy = b->y - a->y;
|
||||
}
|
||||
|
||||
/* Compare two slopes. Slope angles begin at 0 in the direction of the
|
||||
positive X axis and increase in the direction of the positive Y
|
||||
axis.
|
||||
|
||||
WARNING: This function only gives correct results if the angular
|
||||
difference between a and b is less than PI.
|
||||
|
||||
< 0 => a less positive than b
|
||||
== 0 => a equal to be
|
||||
> 0 => a more positive than b
|
||||
*/
|
||||
int
|
||||
_cairo_slope_compare (cairo_slope_t *a, cairo_slope_t *b)
|
||||
{
|
||||
cairo_fixed_48_16_t diff;
|
||||
|
||||
diff = ((cairo_fixed_48_16_t) a->dy * (cairo_fixed_48_16_t) b->dx
|
||||
- (cairo_fixed_48_16_t) b->dy * (cairo_fixed_48_16_t) a->dx);
|
||||
|
||||
if (diff > 0)
|
||||
return 1;
|
||||
if (diff < 0)
|
||||
return -1;
|
||||
|
||||
if (a->dx == 0 && a->dy == 0)
|
||||
return 1;
|
||||
if (b->dx == 0 && b->dy ==0)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* XXX: It might be cleaner to move away from usage of
|
||||
_cairo_slope_clockwise/_cairo_slope_counter_clockwise in favor of
|
||||
directly using _cairo_slope_compare.
|
||||
*/
|
||||
|
||||
/* Is a clockwise of b?
|
||||
*
|
||||
* NOTE: The strict equality here is not significant in and of itself,
|
||||
|
|
@ -43,8 +80,7 @@ _cairo_slope_init (cairo_slope_t *slope, cairo_point_t *a, cairo_point_t *b)
|
|||
int
|
||||
_cairo_slope_clockwise (cairo_slope_t *a, cairo_slope_t *b)
|
||||
{
|
||||
return ((cairo_fixed_48_16_t) b->dy * (cairo_fixed_48_16_t) a->dx
|
||||
> (cairo_fixed_48_16_t) a->dy * (cairo_fixed_48_16_t) b->dx);
|
||||
return _cairo_slope_compare (a, b) < 0;
|
||||
}
|
||||
|
||||
int
|
||||
|
|
|
|||
|
|
@ -222,8 +222,8 @@ typedef struct cairo_pen {
|
|||
double radius;
|
||||
double tolerance;
|
||||
|
||||
cairo_pen_vertex_t *vertices;
|
||||
int num_vertices;
|
||||
cairo_pen_vertex_t *vertex;
|
||||
} cairo_pen_t;
|
||||
|
||||
typedef struct cairo_color cairo_color_t;
|
||||
|
|
@ -715,6 +715,10 @@ _cairo_font_show_text (cairo_font_t *font,
|
|||
double y,
|
||||
const unsigned char *utf8);
|
||||
|
||||
/* cairo_hull.c */
|
||||
extern cairo_status_t
|
||||
_cairo_hull_compute (cairo_pen_vertex_t *vertices, int *num_vertices);
|
||||
|
||||
/* cairo_path.c */
|
||||
extern void __internal_linkage
|
||||
_cairo_path_init (cairo_path_t *path);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue