third_party/cairo/src/cairo-path-stroke-traps.c
static cairo_status_t
line_to_dashed (void *closure, const cairo_point_t *point)
{
    struct stroker *stroker = closure;
    double mag, remain, step_length = 0;
    double slope_dx, slope_dy;
    double dx2, dy2;
    cairo_stroke_face_t sub_start, sub_end;
    const cairo_point_t *p1 = &stroker->current_face.point;
    const cairo_point_t *p2 = point;
    cairo_slope_t dev_slope;
    cairo_line_t segment;
    cairo_bool_t fully_in_bounds;

    stroker->has_initial_sub_path = stroker->dash.dash_starts_on;

    if (p1->x == p2->x && p1->y == p2->y)
	return CAIRO_STATUS_SUCCESS;

    fully_in_bounds = TRUE;
    if (stroker->has_bounds &&
	(! _cairo_box_contains_point (&stroker->join_bounds, p1) ||
	 ! _cairo_box_contains_point (&stroker->join_bounds, p2)))
    {
	fully_in_bounds = FALSE;
    }

    _cairo_slope_init (&dev_slope, p1, p2);

    slope_dx = _cairo_fixed_to_double (p2->x - p1->x);
    slope_dy = _cairo_fixed_to_double (p2->y - p1->y);

    if (stroker->ctm_inverse)
	cairo_matrix_transform_distance (stroker->ctm_inverse, &slope_dx, &slope_dy);
    mag = normalize_slope (&slope_dx, &slope_dy);
    if (mag <= DBL_EPSILON)
	return CAIRO_STATUS_SUCCESS;

    remain = mag;
    segment.p1 = *p1;
    while (remain) {
	step_length = MIN (stroker->dash.dash_remain, remain);
	remain -= step_length;
	dx2 = slope_dx * (mag - remain);
	dy2 = slope_dy * (mag - remain);
	cairo_matrix_transform_distance (stroker->ctm, &dx2, &dy2);
	segment.p2.x = _cairo_fixed_from_double (dx2) + p1->x;
	segment.p2.y = _cairo_fixed_from_double (dy2) + p1->y;

	if (stroker->dash.dash_on &&
	    (fully_in_bounds ||
	     (! stroker->has_first_face && stroker->dash.dash_starts_on) ||
	     _cairo_box_intersects_line_segment (&stroker->join_bounds, &segment)))
	{
	    add_sub_edge (stroker,
			  &segment.p1, &segment.p2,
			  &dev_slope,
			  &sub_start, &sub_end);

	    if (stroker->has_current_face) {
		/* Join with final face from previous segment */
		join (stroker, &stroker->current_face, &sub_start);

		stroker->has_current_face = FALSE;
	    } else if (! stroker->has_first_face && stroker->dash.dash_starts_on) {
		/* Save sub path's first face in case needed for closing join */
		stroker->first_face = sub_start;
		stroker->has_first_face = TRUE;
	    } else {
		/* Cap dash start if not connecting to a previous segment */
		add_leading_cap (stroker, &sub_start);
	    }

	    if (remain) {
		/* Cap dash end if not at end of segment */
		add_trailing_cap (stroker, &sub_end);
	    } else {
		stroker->current_face = sub_end;
		stroker->has_current_face = TRUE;
	    }
	} else {
	    if (stroker->has_current_face) {
		/* Cap final face from previous segment */
		add_trailing_cap (stroker, &stroker->current_face);

		stroker->has_current_face = FALSE;
	    }
	}

	_cairo_stroker_dash_step (&stroker->dash, step_length);
	segment.p1 = segment.p2;
    }

    if (stroker->dash.dash_on && ! stroker->has_current_face) {
	/* This segment ends on a transition to dash_on, compute a new face
	 * and add cap for the beginning of the next dash_on step.
	 *
	 * Note: this will create a degenerate cap if this is not the last line
	 * in the path. Whether this behaviour is desirable or not is debatable.
	 * On one side these degenerate caps can not be reproduced with regular
	 * path stroking.
	 * On the other hand, Acroread 7 also produces the degenerate caps.
	 */
	compute_face (point, &dev_slope, stroker, &stroker->current_face);

	add_leading_cap (stroker, &stroker->current_face);

	stroker->has_current_face = TRUE;
    } else
	stroker->current_face.point = *point;

    return CAIRO_STATUS_SUCCESS;
}
/*
 * Dashed lines.  Cap each dash end, join around turns when on
 */
Dashed lines.  Cap each dash end, join around turns when on
Dashed lines . Cap each dash end join around turns when on
static cairo_status_t
line_to_dashed (void *closure, const cairo_point_t *point)
{
    struct stroker *stroker = closure;
    double mag, remain, step_length = 0;
    double slope_dx, slope_dy;
    double dx2, dy2;
    cairo_stroke_face_t sub_start, sub_end;
    const cairo_point_t *p1 = &stroker->current_face.point;
    const cairo_point_t *p2 = point;
    cairo_slope_t dev_slope;
    cairo_line_t segment;
    cairo_bool_t fully_in_bounds;
    stroker->has_initial_sub_path = stroker->dash.dash_starts_on;
    if (p1->x == p2->x && p1->y == p2->y)
	return CAIRO_STATUS_SUCCESS;
    fully_in_bounds = TRUE;
    if (stroker->has_bounds &&
	(! _cairo_box_contains_point (&stroker->join_bounds, p1) ||
	 ! _cairo_box_contains_point (&stroker->join_bounds, p2)))
    {
	fully_in_bounds = FALSE;
    }
    _cairo_slope_init (&dev_slope, p1, p2);
    slope_dx = _cairo_fixed_to_double (p2->x - p1->x);
    slope_dy = _cairo_fixed_to_double (p2->y - p1->y);
    if (stroker->ctm_inverse)
	cairo_matrix_transform_distance (stroker->ctm_inverse, &slope_dx, &slope_dy);
    mag = normalize_slope (&slope_dx, &slope_dy);
    if (mag <= DBL_EPSILON)
	return CAIRO_STATUS_SUCCESS;
    remain = mag;
    segment.p1 = *p1;
    while (remain) {
	step_length = MIN (stroker->dash.dash_remain, remain);
	remain -= step_length;
	dx2 = slope_dx * (mag - remain);
	dy2 = slope_dy * (mag - remain);
	cairo_matrix_transform_distance (stroker->ctm, &dx2, &dy2);
	segment.p2.x = _cairo_fixed_from_double (dx2) + p1->x;
	segment.p2.y = _cairo_fixed_from_double (dy2) + p1->y;
	if (stroker->dash.dash_on &&
	    (fully_in_bounds ||
	     (! stroker->has_first_face && stroker->dash.dash_starts_on) ||
	     _cairo_box_intersects_line_segment (&stroker->join_bounds, &segment)))
	{
	    add_sub_edge (stroker,
			  &segment.p1, &segment.p2,
			  &dev_slope,
			  &sub_start, &sub_end);
	    if (stroker->has_current_face) {
		join (stroker, &stroker->current_face, &sub_start);
		stroker->has_current_face = FALSE;
	    } else if (! stroker->has_first_face && stroker->dash.dash_starts_on) {
		stroker->first_face = sub_start;
		stroker->has_first_face = TRUE;
	    } else {
		add_leading_cap (stroker, &sub_start);
	    }
	    if (remain) {
		add_trailing_cap (stroker, &sub_end);
	    } else {
		stroker->current_face = sub_end;
		stroker->has_current_face = TRUE;
	    }
	} else {
	    if (stroker->has_current_face) {
		add_trailing_cap (stroker, &stroker->current_face);
		stroker->has_current_face = FALSE;
	    }
	}
	_cairo_stroker_dash_step (&stroker->dash, step_length);
	segment.p1 = segment.p2;
    }
    if (stroker->dash.dash_on && ! stroker->has_current_face) {
	compute_face (point, &dev_slope, stroker, &stroker->current_face);
	add_leading_cap (stroker, &stroker->current_face);
	stroker->has_current_face = TRUE;
    } else
	stroker->current_face.point = *point;
    return CAIRO_STATUS_SUCCESS;
}
static cairo_status_t line_to_dashed ( void * closure , const cairo_point_t * point ) { struct stroker * stroker = closure ; double mag , remain , step_length = 0 ; double slope_dx , slope_dy ; double dx2 , dy2 ; cairo_stroke_face_t sub_start , sub_end ; const cairo_point_t * p1 = & stroker -> current_face . point ; const cairo_point_t * p2 = point ; cairo_slope_t dev_slope ; cairo_line_t segment ; cairo_bool_t fully_in_bounds ; stroker -> has_initial_sub_path = stroker -> dash . dash_starts_on ; if ( p1 -> x == p2 -> x && p1 -> y == p2 -> y ) return CAIRO_STATUS_SUCCESS ; fully_in_bounds = TRUE ; if ( stroker -> has_bounds && ( ! _cairo_box_contains_point ( & stroker -> join_bounds , p1 ) || ! _cairo_box_contains_point ( & stroker -> join_bounds , p2 ) ) ) { fully_in_bounds = FALSE ; } _cairo_slope_init ( & dev_slope , p1 , p2 ) ; slope_dx = _cairo_fixed_to_double ( p2 -> x - p1 -> x ) ; slope_dy = _cairo_fixed_to_double ( p2 -> y - p1 -> y ) ; if ( stroker -> ctm_inverse ) cairo_matrix_transform_distance ( stroker -> ctm_inverse , & slope_dx , & slope_dy ) ; mag = normalize_slope ( & slope_dx , & slope_dy ) ; if ( mag <= DBL_EPSILON ) return CAIRO_STATUS_SUCCESS ; remain = mag ; segment . p1 = * p1 ; while ( remain ) { step_length = MIN ( stroker -> dash . dash_remain , remain ) ; remain -= step_length ; dx2 = slope_dx * ( mag - remain ) ; dy2 = slope_dy * ( mag - remain ) ; cairo_matrix_transform_distance ( stroker -> ctm , & dx2 , & dy2 ) ; segment . p2 . x = _cairo_fixed_from_double ( dx2 ) + p1 -> x ; segment . p2 . y = _cairo_fixed_from_double ( dy2 ) + p1 -> y ; if ( stroker -> dash . dash_on && ( fully_in_bounds || ( ! stroker -> has_first_face && stroker -> dash . dash_starts_on ) || _cairo_box_intersects_line_segment ( & stroker -> join_bounds , & segment ) ) ) { add_sub_edge ( stroker , & segment . p1 , & segment . p2 , & dev_slope , & sub_start , & sub_end ) ; if ( stroker -> has_current_face ) { join ( stroker , & stroker -> current_face , & sub_start ) ; stroker -> has_current_face = FALSE ; } else if ( ! stroker -> has_first_face && stroker -> dash . dash_starts_on ) { stroker -> first_face = sub_start ; stroker -> has_first_face = TRUE ; } else { add_leading_cap ( stroker , & sub_start ) ; } if ( remain ) { add_trailing_cap ( stroker , & sub_end ) ; } else { stroker -> current_face = sub_end ; stroker -> has_current_face = TRUE ; } } else { if ( stroker -> has_current_face ) { add_trailing_cap ( stroker , & stroker -> current_face ) ; stroker -> has_current_face = FALSE ; } } _cairo_stroker_dash_step ( & stroker -> dash , step_length ) ; segment . p1 = segment . p2 ; } if ( stroker -> dash . dash_on && ! stroker -> has_current_face ) { compute_face ( point , & dev_slope , stroker , & stroker -> current_face ) ; add_leading_cap ( stroker , & stroker -> current_face ) ; stroker -> has_current_face = TRUE ; } else stroker -> current_face . point = * point ; return CAIRO_STATUS_SUCCESS ; }
Dashed lines.
Dashed lines .
/* Join with final face from previous segment */ /* Save sub path's first face in case needed for closing join */ /* Cap dash start if not connecting to a previous segment */ /* Cap dash end if not at end of segment */ /* Cap final face from previous segment */ /* This segment ends on a transition to dash_on, compute a new face
	 * and add cap for the beginning of the next dash_on step.
	 *
	 * Note: this will create a degenerate cap if this is not the last line
	 * in the path. Whether this behaviour is desirable or not is debatable.
	 * On one side these degenerate caps can not be reproduced with regular
	 * path stroking.
	 * On the other hand, Acroread 7 also produces the degenerate caps.
	 */