⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cairo-traps.c

📁 按照官方的说法:Cairo is a vector graphics library with cross-device output support. 翻译过来
💻 C
📖 第 1 页 / 共 2 页
字号:
/* XXX: Both _compute_x and _compute_inverse_slope will divide by zero   for horizontal lines. Now, we "know" that when we are tessellating   polygons that the polygon data structure discards all horizontal   edges, but there's nothing here to guarantee that. I suggest the   following:   A) Move all of the polygon tessellation code out of xrtraps.c and      into xrpoly.c, (in order to be in the same module as the code      discarding horizontal lines).   OR   B) Re-implement the line intersection in a way that avoids all      division by zero. Here's one approach. The only disadvantage      might be that that there are not meaningful names for all of the      sub-computations -- just a bunch of determinants. I haven't      looked at complexity, (both are probably similar and it probably      doesn't matter much anyway). *//* XXX: Keith's new intersection code is much cleaner, and uses * sufficient precision for correctly sorting intersections according * to the analysis in Hobby's paper. * * But, when we enable this code, some things are failing, (eg. the * stars in test/fill_rule get filled wrong). This could indicate a * bug in one of tree places: * *	1) The new intersection code in this file * *	2) cairo_wideint.c (which is only exercised here) * *      3) In the current tessellator, (where the old intersection *	   code, with its mystic increments could be masking the bug). * * It will likely be easier to revisit this when the new tessellation * code is in place. So, for now, we'll simply disable the new * intersection code. */#define CAIRO_TRAPS_USE_NEW_INTERSECTION_CODE 0#if CAIRO_TRAPS_USE_NEW_INTERSECTION_CODEstatic const cairo_fixed_32_32_t_det16_32 (cairo_fixed_16_16_t a,	   cairo_fixed_16_16_t b,	   cairo_fixed_16_16_t c,	   cairo_fixed_16_16_t d){    return _cairo_int64_sub (_cairo_int32x32_64_mul (a, d),			     _cairo_int32x32_64_mul (b, c));}static const cairo_fixed_64_64_t_det32_64 (cairo_fixed_32_32_t a,	   cairo_fixed_32_32_t b,	   cairo_fixed_32_32_t c,	   cairo_fixed_32_32_t d){    return _cairo_int128_sub (_cairo_int64x64_128_mul (a, d),			      _cairo_int64x64_128_mul (b, c));}static const cairo_fixed_32_32_t_fixed_16_16_to_fixed_32_32 (cairo_fixed_16_16_t a){    return _cairo_int64_lsl (_cairo_int32_to_int64 (a), 16);}static int_line_segs_intersect_ceil (cairo_line_t *l1, cairo_line_t *l2, cairo_fixed_t *y_intersection){    cairo_fixed_16_16_t	dx1, dx2, dy1, dy2;    cairo_fixed_32_32_t	den_det;    cairo_fixed_32_32_t	l1_det, l2_det;    cairo_fixed_64_64_t num_det;    cairo_fixed_32_32_t	intersect_32_32;    cairo_fixed_48_16_t	intersect_48_16;    cairo_fixed_16_16_t	intersect_16_16;    cairo_quorem128_t	qr;    dx1 = l1->p1.x - l1->p2.x;    dy1 = l1->p1.y - l1->p2.y;    dx2 = l2->p1.x - l2->p2.x;    dy2 = l2->p1.y - l2->p2.y;    den_det = _det16_32 (dx1, dy1,			 dx2, dy2);    if (_cairo_int64_eq (den_det, _cairo_int32_to_int64(0)))	return 0;    l1_det = _det16_32 (l1->p1.x, l1->p1.y,			l1->p2.x, l1->p2.y);    l2_det = _det16_32 (l2->p1.x, l2->p1.y,			l2->p2.x, l2->p2.y);    num_det = _det32_64 (l1_det, _fixed_16_16_to_fixed_32_32 (dy1),			 l2_det, _fixed_16_16_to_fixed_32_32 (dy2));    /*     * Ok, this one is a bit tricky in fixed point, the denominator     * needs to be left with 32-bits of fraction so that the     * result of the divide ends up with 32-bits of fraction (64 - 32 = 32)     */    qr = _cairo_int128_divrem (num_det, _cairo_int64_to_int128 (den_det));    intersect_32_32 = _cairo_int128_to_int64 (qr.quo);    /*     * Find the ceiling of the quotient -- divrem returns     * the quotient truncated towards zero, so if the     * quotient should be positive (num_den and den_det have same sign)     * bump the quotient up by one.     */    if (_cairo_int128_ne (qr.rem, _cairo_int32_to_int128 (0)) &&	(_cairo_int128_ge (num_det, _cairo_int32_to_int128 (0)) ==	 _cairo_int64_ge (den_det, _cairo_int32_to_int64 (0))))    {	intersect_32_32 = _cairo_int64_add (intersect_32_32,					    _cairo_int32_to_int64 (1));    }    /*     * Now convert from 32.32 to 48.16 and take the ceiling;     * this requires adding in 15 1 bits and shifting the result     */    intersect_32_32 = _cairo_int64_add (intersect_32_32,					_cairo_int32_to_int64 ((1 << 16) - 1));    intersect_48_16 = _cairo_int64_rsa (intersect_32_32, 16);    /*     * And drop the top bits     */    intersect_16_16 = _cairo_int64_to_int32 (intersect_48_16);    *y_intersection = intersect_16_16;    return 1;}#endif /* CAIRO_TRAPS_USE_NEW_INTERSECTION_CODE */static cairo_fixed_16_16_t_compute_x (cairo_line_t *line, cairo_fixed_t y){    cairo_fixed_16_16_t dx = line->p2.x - line->p1.x;    cairo_fixed_32_32_t ex = (cairo_fixed_48_16_t) (y - line->p1.y) * (cairo_fixed_48_16_t) dx;    cairo_fixed_16_16_t dy = line->p2.y - line->p1.y;    return line->p1.x + (ex / dy);}#if ! CAIRO_TRAPS_USE_NEW_INTERSECTION_CODEstatic double_compute_inverse_slope (cairo_line_t *l){    return (_cairo_fixed_to_double (l->p2.x - l->p1.x) /	    _cairo_fixed_to_double (l->p2.y - l->p1.y));}static double_compute_x_intercept (cairo_line_t *l, double inverse_slope){    return _cairo_fixed_to_double (l->p1.x) - inverse_slope * _cairo_fixed_to_double (l->p1.y);}static int_line_segs_intersect_ceil (cairo_line_t *l1, cairo_line_t *l2, cairo_fixed_t *y_ret){    /*     * x = m1y + b1     * x = m2y + b2     * m1y + b1 = m2y + b2     * y * (m1 - m2) = b2 - b1     * y = (b2 - b1) / (m1 - m2)     */    cairo_fixed_16_16_t y_intersect;    double  m1 = _compute_inverse_slope (l1);    double  b1 = _compute_x_intercept (l1, m1);    double  m2 = _compute_inverse_slope (l2);    double  b2 = _compute_x_intercept (l2, m2);    if (m1 == m2)	return 0;    y_intersect = _cairo_fixed_from_double ((b2 - b1) / (m1 - m2));    if (m1 < m2) {	cairo_line_t *t;	t = l1;	l1 = l2;	l2 = t;    }    /* Assuming 56 bits of floating point precision, the intersection       is accurate within one sub-pixel coordinate. We must ensure       that we return a value that is at or after the intersection. At       most, we must increment once. */    if (_compute_x (l2, y_intersect) > _compute_x (l1, y_intersect))	y_intersect++;    /* XXX: Hmm... Keith's error calculations said we'd at most be off       by one sub-pixel. But, I found that the paint-fill-BE-01.svg       test from the W3C SVG conformance suite definitely requires two       increments.       It could be that we need one to overcome the error, and another       to round up.       It would be nice to be sure this code is correct, (but we can't       do the while loop as it will work for way to long on       exceedingly distant intersections with large errors that we       really don't care about anyway as they will be ignored by the       calling function.    */    if (_compute_x (l2, y_intersect) > _compute_x (l1, y_intersect))	y_intersect++;    /* XXX: hmm... now I found "intersection_killer" inside xrspline.c       that requires 3 increments. Clearly, we haven't characterized       this completely yet. */    if (_compute_x (l2, y_intersect) > _compute_x (l1, y_intersect))	y_intersect++;    /* I think I've found the answer to our problems. The insight is       that everytime we round we are changing the slopes of the       relevant lines, so we may be introducing new intersections that       we miss, so everything breaks apart. John Hobby wrote a paper       on how to fix this:       [Hobby93c] John D. Hobby, Practical Segment Intersection with       Finite Precision Output, Computation Geometry Theory and       Applications, 13(4), 1999.       Available online (2003-08017):       http://cm.bell-labs.com/cm/cs/doc/93/2-27.ps.gz       Now we just need to go off and implement that.    */    *y_ret = y_intersect;    return 1;}#endif /* CAIRO_TRAPS_USE_NEW_INTERSECTION_CODE *//* The algorithm here is pretty simple:   inactive = [edges]   y = min_p1_y (inactive)   while (num_active || num_inactive) {   	active = all edges containing y	next_y = min ( min_p2_y (active), min_p1_y (inactive), min_intersection (active) )	fill_traps (active, y, next_y, fill_rule)	y = next_y   }   The invariants that hold during fill_traps are:   	All edges in active contain both y and next_y	No edges in active intersect within y and next_y   These invariants mean that fill_traps is as simple as sorting the   active edges, forming a trapezoid between each adjacent pair. Then,   either the even-odd or winding rule is used to determine whether to   emit each of these trapezoids.   Warning: This function obliterates the edges of the polygon provided.*/cairo_status_t_cairo_traps_tessellate_polygon (cairo_traps_t		*traps,				 cairo_polygon_t	*poly,				 cairo_fill_rule_t	fill_rule){    cairo_status_t	status;    int 		i, active, inactive;    cairo_fixed_t	y, y_next, intersect;    int			in_out, num_edges = poly->num_edges;    cairo_edge_t	*edges = poly->edges;    if (num_edges == 0)	return CAIRO_STATUS_SUCCESS;    qsort (edges, num_edges, sizeof (cairo_edge_t), _compare_cairo_edge_by_top);    y = edges[0].edge.p1.y;    active = 0;    inactive = 0;    while (active < num_edges) {	while (inactive < num_edges && edges[inactive].edge.p1.y <= y)	    inactive++;	for (i = active; i < inactive; i++)	    edges[i].current_x = _compute_x (&edges[i].edge, y);	qsort (&edges[active], inactive - active,	       sizeof (cairo_edge_t), _compare_cairo_edge_by_current_x_slope);	/* find next inflection point */	y_next = edges[active].edge.p2.y;	for (i = active; i < inactive; i++) {	    if (edges[i].edge.p2.y < y_next)		y_next = edges[i].edge.p2.y;	    /* check intersect */	    if (i != inactive - 1 && edges[i].current_x != edges[i+1].current_x)		if (_line_segs_intersect_ceil (&edges[i].edge, &edges[i+1].edge,					       &intersect))		    if (intersect > y && intersect < y_next)			y_next = intersect;	}	/* check next inactive point */	if (inactive < num_edges && edges[inactive].edge.p1.y < y_next)	    y_next = edges[inactive].edge.p1.y;	/* walk the active edges generating trapezoids */	in_out = 0;	for (i = active; i < inactive - 1; i++) {	    if (fill_rule == CAIRO_FILL_RULE_WINDING) {		if (edges[i].clockWise)		    in_out++;		else		    in_out--;		if (in_out == 0)		    continue;	    } else {		in_out++;		if ((in_out & 1) == 0)		    continue;	    }	    status = _cairo_traps_add_trap (traps, y, y_next, &edges[i].edge, &edges[i+1].edge);	    if (status)		return status;	}	/* delete inactive edges */	for (i = active; i < inactive; i++) {	    if (edges[i].edge.p2.y <= y_next) {		memmove (&edges[active+1], &edges[active], (i - active) * sizeof (cairo_edge_t));		active++;	    }	}	y = y_next;    }    return CAIRO_STATUS_SUCCESS;}static cairo_bool_t_cairo_trap_contains (cairo_trapezoid_t *t, cairo_point_t *pt){    cairo_slope_t slope_left, slope_pt, slope_right;    if (t->top > pt->y)	return FALSE;    if (t->bottom < pt->y)	return FALSE;    _cairo_slope_init (&slope_left, &t->left.p1, &t->left.p2);    _cairo_slope_init (&slope_pt, &t->left.p1, pt);    if (_cairo_slope_compare (&slope_left, &slope_pt) < 0)	return FALSE;    _cairo_slope_init (&slope_right, &t->right.p1, &t->right.p2);    _cairo_slope_init (&slope_pt, &t->right.p1, pt);    if (_cairo_slope_compare (&slope_pt, &slope_right) < 0)	return FALSE;    return TRUE;}cairo_bool_t_cairo_traps_contain (cairo_traps_t *traps, double x, double y){    int i;    cairo_point_t point;    point.x = _cairo_fixed_from_double (x);    point.y = _cairo_fixed_from_double (y);    for (i = 0; i < traps->num_traps; i++) {	if (_cairo_trap_contains (&traps->traps[i], &point))	    return TRUE;    }    return FALSE;}void_cairo_traps_extents (cairo_traps_t *traps, cairo_box_t *extents){    *extents = traps->extents;}/** * _cairo_traps_extract_region: * @traps: a #cairo_traps_t * @region: on return, %NULL is stored here if the trapezoids aren't *          exactly representable as a pixman region, otherwise a *          a pointer to such a region, newly allocated. *          (free with pixman region destroy) * * Determines if a set of trapezoids are exactly representable as a * pixman region, and if so creates such a region. * * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY **/cairo_status_t_cairo_traps_extract_region (cairo_traps_t      *traps,			     pixman_region16_t **region){    int i;    for (i = 0; i < traps->num_traps; i++)	if (!(traps->traps[i].left.p1.x == traps->traps[i].left.p2.x	      && traps->traps[i].right.p1.x == traps->traps[i].right.p2.x	      && _cairo_fixed_is_integer(traps->traps[i].top)	      && _cairo_fixed_is_integer(traps->traps[i].bottom)	      && _cairo_fixed_is_integer(traps->traps[i].left.p1.x)	      && _cairo_fixed_is_integer(traps->traps[i].right.p1.x))) {	    *region = NULL;	    return CAIRO_STATUS_SUCCESS;	}    *region = pixman_region_create ();    for (i = 0; i < traps->num_traps; i++) {	int x = _cairo_fixed_integer_part(traps->traps[i].left.p1.x);	int y = _cairo_fixed_integer_part(traps->traps[i].top);	int width = _cairo_fixed_integer_part(traps->traps[i].right.p1.x) - x;	int height = _cairo_fixed_integer_part(traps->traps[i].bottom) - y;	/* XXX: Sometimes we get degenerate trapezoids from the tesellator,	 * if we call pixman_region_union_rect(), it bizarrly fails on such	 * an empty rectangle, so skip them.	 */	if (width == 0 || height == 0)	  continue;	if (pixman_region_union_rect (*region, *region,				      x, y, width, height) != PIXMAN_REGION_STATUS_SUCCESS) {	    pixman_region_destroy (*region);	    return CAIRO_STATUS_NO_MEMORY;	}    }    return CAIRO_STATUS_SUCCESS;}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -