Subversion Repositories Kolibri OS

Rev

Rev 1892 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 1892 Rev 3959
Line 37... Line 37...
37
 */
37
 */
Line 38... Line 38...
38
 
38
 
39
#define _BSD_SOURCE /* for hypot() */
39
#define _BSD_SOURCE /* for hypot() */
Line -... Line 40...
-
 
40
#include "cairoint.h"
40
#include "cairoint.h"
41
 
41
 
42
#include "cairo-box-inline.h"
42
#include "cairo-boxes-private.h"
43
#include "cairo-boxes-private.h"
43
#include "cairo-error-private.h"
44
#include "cairo-error-private.h"
44
#include "cairo-path-fixed-private.h"
-
 
45
#include "cairo-slope-private.h"
45
#include "cairo-path-fixed-private.h"
46
 
-
 
47
typedef struct _cairo_stroker_dash {
-
 
48
    cairo_bool_t dashed;
-
 
49
    unsigned int dash_index;
-
 
50
    cairo_bool_t dash_on;
-
 
51
    cairo_bool_t dash_starts_on;
-
 
52
    double dash_remain;
-
 
53
 
-
 
54
    double dash_offset;
-
 
55
    const double *dashes;
46
#include "cairo-slope-private.h"
Line 56... Line 47...
56
    unsigned int num_dashes;
47
#include "cairo-stroke-dash-private.h"
57
} cairo_stroker_dash_t;
48
#include "cairo-traps-private.h"
Line 58... Line 49...
58
 
49
 
59
typedef struct cairo_stroker {
50
typedef struct cairo_stroker {
-
 
51
    cairo_stroke_style_t style;
60
    cairo_stroke_style_t style;
52
 
-
 
53
    const cairo_matrix_t *ctm;
61
 
54
    const cairo_matrix_t *ctm_inverse;
62
    const cairo_matrix_t *ctm;
55
    double half_line_width;
Line 63... Line 56...
63
    const cairo_matrix_t *ctm_inverse;
56
    double tolerance;
64
    double tolerance;
57
    double spline_cusp_tolerance;
Line 96... Line 89...
96
    cairo_bool_t has_bounds;
89
    cairo_bool_t has_bounds;
97
    cairo_box_t bounds;
90
    cairo_box_t bounds;
98
} cairo_stroker_t;
91
} cairo_stroker_t;
Line 99... Line 92...
99
 
92
 
100
static void
93
static void
-
 
94
_cairo_stroker_limit (cairo_stroker_t *stroker,
-
 
95
		      const cairo_path_fixed_t *path,
-
 
96
		      const cairo_box_t *boxes,
101
_cairo_stroker_dash_start (cairo_stroker_dash_t *dash)
97
		      int num_boxes)
102
{
98
{
103
    double offset;
99
    double dx, dy;
104
    cairo_bool_t on = TRUE;
-
 
105
    unsigned int i = 0;
-
 
106
 
-
 
107
    if (! dash->dashed)
-
 
108
	return;
-
 
109
 
-
 
110
    offset = dash->dash_offset;
-
 
111
 
-
 
112
    /* We stop searching for a starting point as soon as the
-
 
113
       offset reaches zero.  Otherwise when an initial dash
-
 
114
       segment shrinks to zero it will be skipped over. */
-
 
115
    while (offset > 0.0 && offset >= dash->dashes[i]) {
-
 
116
	offset -= dash->dashes[i];
-
 
117
	on = !on;
-
 
118
	if (++i == dash->num_dashes)
-
 
119
	    i = 0;
-
 
Line 120... Line 100...
120
    }
100
    cairo_fixed_t fdx, fdy;
121
 
-
 
122
    dash->dash_index = i;
101
 
123
    dash->dash_on = dash->dash_starts_on = on;
-
 
Line 124... Line -...
124
    dash->dash_remain = dash->dashes[i] - offset;
-
 
125
}
102
    stroker->has_bounds = TRUE;
126
 
-
 
127
static void
-
 
128
_cairo_stroker_dash_step (cairo_stroker_dash_t *dash, double step)
103
    _cairo_boxes_get_extents (boxes, num_boxes, &stroker->bounds);
129
{
104
 
130
    dash->dash_remain -= step;
105
    /* Extend the bounds in each direction to account for the maximum area
Line 131... Line 106...
131
    if (dash->dash_remain <= 0.) {
106
     * we might generate trapezoids, to capture line segments that are outside
132
	if (++dash->dash_index == dash->num_dashes)
107
     * of the bounds but which might generate rendering that's within bounds.
133
	    dash->dash_index = 0;
-
 
134
 
-
 
Line 135... Line -...
135
	dash->dash_on = ! dash->dash_on;
-
 
136
	dash->dash_remain = dash->dashes[dash->dash_index];
-
 
137
    }
108
     */
138
}
-
 
139
 
109
 
140
static void
-
 
141
_cairo_stroker_dash_init (cairo_stroker_dash_t *dash,
-
 
142
			  const cairo_stroke_style_t *style)
-
 
143
{
-
 
144
    dash->dashed = style->dash != NULL;
-
 
145
    if (! dash->dashed)
-
 
Line -... Line 110...
-
 
110
    _cairo_stroke_style_max_distance_from_path (&stroker->style, path,
-
 
111
						stroker->ctm, &dx, &dy);
-
 
112
 
146
	return;
113
    fdx = _cairo_fixed_from_double (dx);
-
 
114
    fdy = _cairo_fixed_from_double (dy);
147
 
115
 
Line 148... Line 116...
148
    dash->dashes = style->dash;
116
    stroker->bounds.p1.x -= fdx;
149
    dash->num_dashes = style->num_dashes;
117
    stroker->bounds.p2.x += fdx;
-
 
118
 
150
    dash->dash_offset = style->dash_offset;
119
    stroker->bounds.p1.y -= fdy;
151
 
120
    stroker->bounds.p2.y += fdy;
152
    _cairo_stroker_dash_start (dash);
121
}
153
}
122
 
-
 
123
static cairo_status_t
-
 
124
_cairo_stroker_init (cairo_stroker_t		*stroker,
154
 
125
		     const cairo_path_fixed_t	*path,
155
static cairo_status_t
126
		     const cairo_stroke_style_t	*stroke_style,
Line 156... Line 127...
156
_cairo_stroker_init (cairo_stroker_t		*stroker,
127
		     const cairo_matrix_t	*ctm,
157
		     const cairo_stroke_style_t	*stroke_style,
128
		     const cairo_matrix_t	*ctm_inverse,
158
		     const cairo_matrix_t	*ctm,
129
		     double			 tolerance,
159
		     const cairo_matrix_t	*ctm_inverse,
130
		     const cairo_box_t		*limits,
-
 
131
		     int			 num_limits)
-
 
132
{
-
 
133
    cairo_status_t status;
-
 
134
 
-
 
135
    stroker->style = *stroke_style;
-
 
136
    stroker->ctm = ctm;
-
 
137
    stroker->ctm_inverse = ctm_inverse;
-
 
138
    stroker->tolerance = tolerance;
-
 
139
    stroker->half_line_width = stroke_style->line_width / 2.0;
-
 
140
 
-
 
141
    /* To test whether we need to join two segments of a spline using
-
 
142
     * a round-join or a bevel-join, we can inspect the angle between the
-
 
143
     * two segments. If the difference between the chord distance
Line 160... Line 144...
160
		     double			 tolerance)
144
     * (half-line-width times the cosine of the bisection angle) and the
161
{
145
     * half-line-width itself is greater than tolerance then we need to
Line 162... Line 146...
162
    cairo_status_t status;
146
     * inject a point.
163
 
147
     */
164
    stroker->style = *stroke_style;
-
 
165
    stroker->ctm = ctm;
148
    stroker->spline_cusp_tolerance = 1 - tolerance / stroker->half_line_width;
166
    stroker->ctm_inverse = ctm_inverse;
149
    stroker->spline_cusp_tolerance *= stroker->spline_cusp_tolerance;
Line 167... Line -...
167
    stroker->tolerance = tolerance;
-
 
168
 
-
 
169
    stroker->ctm_determinant = _cairo_matrix_compute_determinant (stroker->ctm);
150
    stroker->spline_cusp_tolerance *= 2;
170
    stroker->ctm_det_positive = stroker->ctm_determinant >= 0.0;
151
    stroker->spline_cusp_tolerance -= 1;
171
 
152
 
Line 172... Line 153...
172
    status = _cairo_pen_init (&stroker->pen,
153
    stroker->ctm_determinant = _cairo_matrix_compute_determinant (stroker->ctm);
Line 173... Line 154...
173
		              stroke_style->line_width / 2.0,
154
    stroker->ctm_det_positive = stroker->ctm_determinant >= 0.0;
Line 174... Line -...
174
			      tolerance, ctm);
-
 
175
    if (unlikely (status))
-
 
176
	return status;
-
 
177
 
-
 
178
    stroker->has_bounds = FALSE;
-
 
179
 
-
 
180
    stroker->has_current_face = FALSE;
-
 
181
    stroker->has_first_face = FALSE;
-
 
182
    stroker->has_initial_sub_path = FALSE;
-
 
183
 
-
 
184
    _cairo_stroker_dash_init (&stroker->dash, stroke_style);
-
 
185
 
155
 
186
    stroker->add_external_edge = NULL;
-
 
187
 
-
 
188
    return CAIRO_STATUS_SUCCESS;
-
 
189
}
-
 
190
 
-
 
191
static void
156
    status = _cairo_pen_init (&stroker->pen,
192
_cairo_stroker_limit (cairo_stroker_t *stroker,
-
 
193
		      const cairo_box_t *boxes,
157
			      stroker->half_line_width, tolerance, ctm);
194
		      int num_boxes)
-
 
195
{
-
 
196
    double dx, dy;
-
 
197
    cairo_fixed_t fdx, fdy;
-
 
198
 
-
 
199
    stroker->has_bounds = TRUE;
-
 
200
    _cairo_boxes_get_extents (boxes, num_boxes, &stroker->bounds);
-
 
Line 201... Line -...
201
 
-
 
202
    /* Extend the bounds in each direction to account for the maximum area
158
    if (unlikely (status))
203
     * we might generate trapezoids, to capture line segments that are outside
159
	return status;
Line 204... Line 160...
204
     * of the bounds but which might generate rendering that's within bounds.
160
 
205
     */
161
    stroker->has_current_face = FALSE;
206
 
162
    stroker->has_first_face = FALSE;
Line 241... Line 197...
241
 
197
 
242
    return _cairo_slope_compare (&in_slope, &out_slope) < 0;
198
    return _cairo_slope_compare (&in_slope, &out_slope) < 0;
Line 243... Line 199...
243
}
199
}
244
 
200
 
245
/**
201
/**
246
 * _cairo_slope_compare_sgn
202
 * _cairo_slope_compare_sgn:
247
 *
203
 *
248
 * Return -1, 0 or 1 depending on the relative slopes of
204
 * Return -1, 0 or 1 depending on the relative slopes of
249
 * two lines.
205
 * two lines.
250
 */
206
 **/
251
static int
207
static int
252
_cairo_slope_compare_sgn (double dx1, double dy1, double dx2, double dy2)
208
_cairo_slope_compare_sgn (double dx1, double dy1, double dx2, double dy2)
Line 281... Line 237...
281
		 const cairo_point_t *inpt,
237
		 const cairo_point_t *inpt,
282
		 const cairo_point_t *outpt,
238
		 const cairo_point_t *outpt,
283
		 cairo_bool_t clockwise)
239
		 cairo_bool_t clockwise)
284
{
240
{
285
    cairo_point_t stack_points[64], *points = stack_points;
241
    cairo_point_t stack_points[64], *points = stack_points;
-
 
242
    cairo_pen_t *pen = &stroker->pen;
286
    int start, stop, step, i, npoints;
243
    int start, stop, num_points = 0;
287
    cairo_status_t status;
244
    cairo_status_t status;
Line -... Line 245...
-
 
245
 
-
 
246
    if (stroker->has_bounds &&
-
 
247
	! _cairo_box_contains_point (&stroker->bounds, midpt))
-
 
248
	goto BEVEL;
-
 
249
 
-
 
250
    assert (stroker->pen.num_vertices);
288
 
251
 
-
 
252
    if (clockwise) {
-
 
253
	_cairo_pen_find_active_ccw_vertices (pen,
-
 
254
					     in_vector, out_vector,
-
 
255
					     &start, &stop);
-
 
256
	if (stroker->add_external_edge) {
289
    if (clockwise) {
257
	    cairo_point_t last;
-
 
258
	    last = *inpt;
-
 
259
	    while (start != stop) {
-
 
260
		cairo_point_t p = *midpt;
Line 290... Line 261...
290
	step  = -1;
261
		_translate_point (&p, &pen->vertices[start].point);
291
 
262
 
292
	start = _cairo_pen_find_active_ccw_vertex_index (&stroker->pen,
-
 
293
							 in_vector);
263
		status = stroker->add_external_edge (stroker->closure,
294
	if (_cairo_slope_compare (&stroker->pen.vertices[start].slope_ccw,
-
 
295
				  in_vector) < 0)
-
 
296
	    start = _range_step (start, -1, stroker->pen.num_vertices);
-
 
297
 
264
						     &last, &p);
298
	stop  = _cairo_pen_find_active_ccw_vertex_index (&stroker->pen,
-
 
299
							 out_vector);
-
 
300
	if (_cairo_slope_compare (&stroker->pen.vertices[stop].slope_cw,
-
 
301
				  out_vector) > 0)
-
 
302
	{
-
 
303
	    stop = _range_step (stop, 1, stroker->pen.num_vertices);
-
 
304
	    if (_cairo_slope_compare (&stroker->pen.vertices[stop].slope_ccw,
-
 
305
				      in_vector) < 0)
265
		if (unlikely (status))
306
	    {
-
 
307
		goto BEVEL;
-
 
Line 308... Line 266...
308
	    }
266
		    return status;
-
 
267
		last = p;
-
 
268
 
-
 
269
		if (start-- == 0)
-
 
270
		    start += pen->num_vertices;
309
	}
271
	    }
310
 
-
 
311
	npoints = start - stop;
-
 
312
    } else {
-
 
313
	step  = 1;
-
 
314
 
-
 
315
	start = _cairo_pen_find_active_cw_vertex_index (&stroker->pen,
272
	    status = stroker->add_external_edge (stroker->closure,
316
							in_vector);
-
 
317
	if (_cairo_slope_compare (&stroker->pen.vertices[start].slope_cw,
-
 
318
				  in_vector) < 0)
-
 
319
	    start = _range_step (start, 1, stroker->pen.num_vertices);
-
 
320
 
-
 
321
	stop  = _cairo_pen_find_active_cw_vertex_index (&stroker->pen,
-
 
322
							out_vector);
-
 
323
	if (_cairo_slope_compare (&stroker->pen.vertices[stop].slope_ccw,
-
 
324
				  out_vector) > 0)
-
 
325
	{
-
 
326
	    stop = _range_step (stop, -1, stroker->pen.num_vertices);
-
 
327
	    if (_cairo_slope_compare (&stroker->pen.vertices[stop].slope_cw,
273
						 &last, outpt);
328
				      in_vector) < 0)
-
 
329
	    {
-
 
Line 330... Line 274...
330
		goto BEVEL;
274
	} else {
-
 
275
	    if (start == stop)
-
 
276
		goto BEVEL;
-
 
277
 
-
 
278
	    num_points = stop - start;
-
 
279
	    if (num_points < 0)
-
 
280
		num_points += pen->num_vertices;
-
 
281
	    num_points += 2;
331
	    }
282
	    if (num_points > ARRAY_LENGTH(stack_points)) {
332
	}
-
 
Line -... Line 283...
-
 
283
		points = _cairo_malloc_ab (num_points, sizeof (cairo_point_t));
333
 
284
		if (unlikely (points == NULL))
-
 
285
		    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
 
286
	    }
-
 
287
 
-
 
288
	    points[0] = *inpt;
-
 
289
	    num_points = 1;
-
 
290
	    while (start != stop) {
334
	npoints = stop - start;
291
		points[num_points] = *midpt;
-
 
292
		_translate_point (&points[num_points], &pen->vertices[start].point);
-
 
293
		num_points++;
-
 
294
 
-
 
295
		if (start-- == 0)
-
 
296
		    start += pen->num_vertices;
-
 
297
	    }
-
 
298
	    points[num_points++] = *outpt;
-
 
299
	}
335
    }
300
    } else {
-
 
301
	_cairo_pen_find_active_cw_vertices (pen,
-
 
302
					    in_vector, out_vector,
-
 
303
					    &start, &stop);
-
 
304
	if (stroker->add_external_edge) {
Line -... Line 305...
-
 
305
	    cairo_point_t last;
-
 
306
	    last = *inpt;
-
 
307
	    while (start != stop) {
-
 
308
		cairo_point_t p = *midpt;
-
 
309
		_translate_point (&p, &pen->vertices[start].point);
-
 
310
 
-
 
311
		status = stroker->add_external_edge (stroker->closure,
-
 
312
						     &p, &last);
-
 
313
		if (unlikely (status))
-
 
314
		    return status;
-
 
315
		last = p;
-
 
316
 
336
    stop = _range_step (stop, step, stroker->pen.num_vertices);
317
		if (++start == pen->num_vertices)
337
 
318
		    start = 0;
Line -... Line 319...
-
 
319
	    }
-
 
320
	    status = stroker->add_external_edge (stroker->closure,
-
 
321
						 outpt, &last);
-
 
322
	} else {
338
    if (npoints < 0)
323
	    if (start == stop)
339
	npoints += stroker->pen.num_vertices;
324
		goto BEVEL;
340
    npoints += 3;
325
 
341
 
326
	    num_points = stop - start;
342
    if (npoints <= 1)
327
	    if (num_points < 0)
Line -... Line 328...
-
 
328
		num_points += pen->num_vertices;
-
 
329
	    num_points += 2;
-
 
330
	    if (num_points > ARRAY_LENGTH(stack_points)) {
-
 
331
		points = _cairo_malloc_ab (num_points, sizeof (cairo_point_t));
-
 
332
		if (unlikely (points == NULL))
-
 
333
		    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
Line 343... Line 334...
343
	goto BEVEL;
334
	    }
344
 
335
 
345
    if (npoints > ARRAY_LENGTH (stack_points)) {
-
 
346
	points = _cairo_malloc_ab (npoints, sizeof (cairo_point_t));
-
 
347
	if (unlikely (points == NULL))
-
 
348
	    return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
 
349
    }
-
 
350
 
-
 
351
 
-
 
352
    /* Construct the fan. */
-
 
353
    npoints = 0;
336
	    points[0] = *inpt;
354
    points[npoints++] = *inpt;
337
	    num_points = 1;
355
    for (i = start;
-
 
356
	 i != stop;
-
 
357
	i = _range_step (i, step, stroker->pen.num_vertices))
-
 
358
    {
-
 
359
	points[npoints] = *midpt;
-
 
360
	_translate_point (&points[npoints], &stroker->pen.vertices[i].point);
-
 
361
	npoints++;
-
 
362
    }
-
 
363
    points[npoints++] = *outpt;
-
 
364
 
338
	    while (start != stop) {
365
    if (stroker->add_external_edge != NULL) {
-
 
366
	for (i = 0; i < npoints - 1; i++) {
-
 
367
	    if (clockwise) {
339
		points[num_points] = *midpt;
-
 
340
		_translate_point (&points[num_points], &pen->vertices[start].point);
368
		status = stroker->add_external_edge (stroker->closure,
341
		num_points++;
369
						     &points[i], &points[i+1]);
342
 
370
	    } else {
343
		if (++start == pen->num_vertices)
371
		status = stroker->add_external_edge (stroker->closure,
344
		    start = 0;
Line 372... Line 345...
372
						     &points[i+1], &points[i]);
345
	    }
373
	    }
346
	    points[num_points++] = *outpt;
Line 676... Line 649...
676
	cairo_slope_t	fvector;
649
	cairo_slope_t	fvector;
677
	cairo_point_t	quad[4];
650
	cairo_point_t	quad[4];
Line 678... Line 651...
678
 
651
 
679
	dx = f->usr_vector.x;
652
	dx = f->usr_vector.x;
680
	dy = f->usr_vector.y;
653
	dy = f->usr_vector.y;
681
	dx *= stroker->style.line_width / 2.0;
654
	dx *= stroker->half_line_width;
682
	dy *= stroker->style.line_width / 2.0;
655
	dy *= stroker->half_line_width;
683
	cairo_matrix_transform_distance (stroker->ctm, &dx, &dy);
656
	cairo_matrix_transform_distance (stroker->ctm, &dx, &dy);
684
	fvector.dx = _cairo_fixed_from_double (dx);
657
	fvector.dx = _cairo_fixed_from_double (dx);
Line 685... Line 658...
685
	fvector.dy = _cairo_fixed_from_double (dy);
658
	fvector.dy = _cairo_fixed_from_double (dy);
Line 799... Line 772...
799
 
772
 
800
    return TRUE;
773
    return TRUE;
Line 801... Line 774...
801
}
774
}
802
 
775
 
-
 
776
static void
803
static void
777
_compute_face (const cairo_point_t *point,
-
 
778
	       const cairo_slope_t *dev_slope,
-
 
779
	       double slope_dx,
804
_compute_face (const cairo_point_t *point, cairo_slope_t *dev_slope,
780
	       double slope_dy,
805
	       double slope_dx, double slope_dy,
781
	       cairo_stroker_t *stroker,
806
	       cairo_stroker_t *stroker, cairo_stroke_face_t *face)
782
	       cairo_stroke_face_t *face)
807
{
783
{
Line 808... Line 784...
808
    double face_dx, face_dy;
784
    double face_dx, face_dy;
Line 815... Line 791...
815
     * whether the ctm reflects or not, and that can be determined
791
     * whether the ctm reflects or not, and that can be determined
816
     * by looking at the determinant of the matrix.
792
     * by looking at the determinant of the matrix.
817
     */
793
     */
818
    if (stroker->ctm_det_positive)
794
    if (stroker->ctm_det_positive)
819
    {
795
    {
820
	face_dx = - slope_dy * (stroker->style.line_width / 2.0);
796
	face_dx = - slope_dy * stroker->half_line_width;
821
	face_dy = slope_dx * (stroker->style.line_width / 2.0);
797
	face_dy = slope_dx * stroker->half_line_width;
822
    }
798
    }
823
    else
799
    else
824
    {
800
    {
825
	face_dx = slope_dy * (stroker->style.line_width / 2.0);
801
	face_dx = slope_dy * stroker->half_line_width;
826
	face_dy = - slope_dx * (stroker->style.line_width / 2.0);
802
	face_dy = - slope_dx * stroker->half_line_width;
827
    }
803
    }
Line 828... Line 804...
828
 
804
 
829
    /* back to device space */
805
    /* back to device space */
Line 855... Line 831...
855
 
831
 
856
    /* check for a degenerative sub_path */
832
    /* check for a degenerative sub_path */
857
    if (stroker->has_initial_sub_path
833
    if (stroker->has_initial_sub_path
858
	&& ! stroker->has_first_face
834
	&& ! stroker->has_first_face
859
	&& ! stroker->has_current_face
835
	&& ! stroker->has_current_face
860
	&& stroker->style.line_cap == CAIRO_LINE_JOIN_ROUND)
836
	&& stroker->style.line_cap == CAIRO_LINE_CAP_ROUND)
861
    {
837
    {
862
	/* pick an arbitrary slope to use */
838
	/* pick an arbitrary slope to use */
863
	double dx = 1.0, dy = 0.0;
839
	double dx = 1.0, dy = 0.0;
864
	cairo_slope_t slope = { CAIRO_FIXED_ONE, 0 };
840
	cairo_slope_t slope = { CAIRO_FIXED_ONE, 0 };
Line 1017... Line 993...
1017
    stroker->current_point = *point;
993
    stroker->current_point = *point;
Line 1018... Line 994...
1018
 
994
 
1019
    return CAIRO_STATUS_SUCCESS;
995
    return CAIRO_STATUS_SUCCESS;
Line -... Line 996...
-
 
996
}
-
 
997
 
-
 
998
static cairo_status_t
-
 
999
_cairo_stroker_spline_to (void *closure,
-
 
1000
			  const cairo_point_t *point,
-
 
1001
			  const cairo_slope_t *tangent)
-
 
1002
{
-
 
1003
    cairo_stroker_t *stroker = closure;
-
 
1004
    cairo_stroke_face_t new_face;
-
 
1005
    double slope_dx, slope_dy;
-
 
1006
    cairo_point_t points[3];
-
 
1007
    cairo_point_t intersect_point;
-
 
1008
 
-
 
1009
    stroker->has_initial_sub_path = TRUE;
-
 
1010
 
-
 
1011
    if (stroker->current_point.x == point->x &&
-
 
1012
	stroker->current_point.y == point->y)
-
 
1013
	return CAIRO_STATUS_SUCCESS;
-
 
1014
 
-
 
1015
    slope_dx = _cairo_fixed_to_double (tangent->dx);
-
 
1016
    slope_dy = _cairo_fixed_to_double (tangent->dy);
-
 
1017
 
-
 
1018
    if (! _compute_normalized_device_slope (&slope_dx, &slope_dy,
-
 
1019
					    stroker->ctm_inverse, NULL))
-
 
1020
	return CAIRO_STATUS_SUCCESS;
-
 
1021
 
-
 
1022
    _compute_face (point, tangent,
-
 
1023
		   slope_dx, slope_dy,
-
 
1024
		   stroker, &new_face);
-
 
1025
 
-
 
1026
    assert (stroker->has_current_face);
-
 
1027
 
-
 
1028
    if ((new_face.dev_slope.x * stroker->current_face.dev_slope.x +
-
 
1029
         new_face.dev_slope.y * stroker->current_face.dev_slope.y) < stroker->spline_cusp_tolerance) {
-
 
1030
 
-
 
1031
	const cairo_point_t *inpt, *outpt;
-
 
1032
	int clockwise = _cairo_stroker_join_is_clockwise (&new_face,
-
 
1033
							  &stroker->current_face);
-
 
1034
 
-
 
1035
	if (clockwise) {
-
 
1036
	    inpt = &stroker->current_face.cw;
-
 
1037
	    outpt = &new_face.cw;
-
 
1038
	} else {
-
 
1039
	    inpt = &stroker->current_face.ccw;
-
 
1040
	    outpt = &new_face.ccw;
-
 
1041
	}
-
 
1042
 
-
 
1043
	_tessellate_fan (stroker,
-
 
1044
			 &stroker->current_face.dev_vector,
-
 
1045
			 &new_face.dev_vector,
-
 
1046
			 &stroker->current_face.point,
-
 
1047
			 inpt, outpt,
-
 
1048
			 clockwise);
-
 
1049
    }
-
 
1050
 
-
 
1051
    if (_slow_segment_intersection (&stroker->current_face.cw,
-
 
1052
				    &stroker->current_face.ccw,
-
 
1053
				    &new_face.cw,
-
 
1054
				    &new_face.ccw,
-
 
1055
				    &intersect_point)) {
-
 
1056
	points[0] = stroker->current_face.ccw;
-
 
1057
	points[1] = new_face.ccw;
-
 
1058
	points[2] = intersect_point;
-
 
1059
	stroker->add_triangle (stroker->closure, points);
-
 
1060
 
-
 
1061
	points[0] = stroker->current_face.cw;
-
 
1062
	points[1] = new_face.cw;
-
 
1063
	stroker->add_triangle (stroker->closure, points);
-
 
1064
    } else {
-
 
1065
	points[0] = stroker->current_face.ccw;
-
 
1066
	points[1] = stroker->current_face.cw;
-
 
1067
	points[2] = new_face.cw;
-
 
1068
	stroker->add_triangle (stroker->closure, points);
-
 
1069
 
-
 
1070
	points[0] = stroker->current_face.ccw;
-
 
1071
	points[1] = new_face.cw;
-
 
1072
	points[2] = new_face.ccw;
-
 
1073
	stroker->add_triangle (stroker->closure, points);
-
 
1074
    }
-
 
1075
 
-
 
1076
    stroker->current_face = new_face;
-
 
1077
    stroker->has_current_face = TRUE;
-
 
1078
    stroker->current_point = *point;
-
 
1079
 
-
 
1080
    return CAIRO_STATUS_SUCCESS;
1020
}
1081
}
1021
 
1082
 
1022
/*
1083
/*
1023
 * Dashed lines.  Cap each dash end, join around turns when on
1084
 * Dashed lines.  Cap each dash end, join around turns when on
1024
 */
1085
 */
Line 1173... Line 1234...
1173
    cairo_stroker_t *stroker = closure;
1234
    cairo_stroker_t *stroker = closure;
1174
    cairo_spline_t spline;
1235
    cairo_spline_t spline;
1175
    cairo_line_join_t line_join_save;
1236
    cairo_line_join_t line_join_save;
1176
    cairo_stroke_face_t face;
1237
    cairo_stroke_face_t face;
1177
    double slope_dx, slope_dy;
1238
    double slope_dx, slope_dy;
1178
    cairo_path_fixed_line_to_func_t *line_to;
1239
    cairo_spline_add_point_func_t line_to;
-
 
1240
    cairo_spline_add_point_func_t spline_to;
1179
    cairo_status_t status = CAIRO_STATUS_SUCCESS;
1241
    cairo_status_t status = CAIRO_STATUS_SUCCESS;
Line 1180... Line 1242...
1180
 
1242
 
1181
    line_to = stroker->dash.dashed ?
1243
    line_to = stroker->dash.dashed ?
1182
	_cairo_stroker_line_to_dashed :
1244
	(cairo_spline_add_point_func_t) _cairo_stroker_line_to_dashed :
-
 
1245
	(cairo_spline_add_point_func_t) _cairo_stroker_line_to;
-
 
1246
 
-
 
1247
    /* spline_to is only capable of rendering non-degenerate splines. */
-
 
1248
    spline_to = stroker->dash.dashed ?
-
 
1249
	(cairo_spline_add_point_func_t) _cairo_stroker_line_to_dashed :
Line 1183... Line 1250...
1183
	_cairo_stroker_line_to;
1250
	(cairo_spline_add_point_func_t) _cairo_stroker_spline_to;
-
 
1251
 
1184
 
1252
    if (! _cairo_spline_init (&spline,
1185
    if (! _cairo_spline_init (&spline,
1253
			      spline_to,
1186
			      line_to, stroker,
1254
			      stroker,
-
 
1255
			      &stroker->current_point, b, c, d))
-
 
1256
    {
1187
			      &stroker->current_point, b, c, d))
1257
	cairo_slope_t fallback_slope;
1188
    {
1258
	_cairo_slope_init (&fallback_slope, &stroker->current_point, d);
Line 1189... Line 1259...
1189
	return line_to (closure, d);
1259
	return line_to (closure, d, &fallback_slope);
1190
    }
1260
    }
1191
 
1261
 
Line 1305... Line 1375...
1305
				    void *closure)
1375
				    void *closure)
1306
{
1376
{
1307
    cairo_stroker_t stroker;
1377
    cairo_stroker_t stroker;
1308
    cairo_status_t status;
1378
    cairo_status_t status;
Line 1309... Line 1379...
1309
 
1379
 
1310
    status = _cairo_stroker_init (&stroker, stroke_style,
1380
    status = _cairo_stroker_init (&stroker, path, stroke_style,
-
 
1381
			          ctm, ctm_inverse, tolerance,
1311
			          ctm, ctm_inverse, tolerance);
1382
				  NULL, 0);
1312
    if (unlikely (status))
1383
    if (unlikely (status))
Line 1313... Line 1384...
1313
	return status;
1384
	return status;
1314
 
1385
 
1315
    stroker.add_triangle = add_triangle;
1386
    stroker.add_triangle = add_triangle;
1316
    stroker.add_triangle_fan = add_triangle_fan;
1387
    stroker.add_triangle_fan = add_triangle_fan;
Line 1317... Line 1388...
1317
    stroker.add_convex_quad = add_convex_quad;
1388
    stroker.add_convex_quad = add_convex_quad;
1318
    stroker.closure = closure;
-
 
1319
 
1389
    stroker.closure = closure;
1320
    status = _cairo_path_fixed_interpret (path,
1390
 
1321
					  CAIRO_DIRECTION_FORWARD,
1391
    status = _cairo_path_fixed_interpret (path,
1322
					  _cairo_stroker_move_to,
1392
					  _cairo_stroker_move_to,
1323
					  stroker.dash.dashed ?
1393
					  stroker.dash.dashed ?
Line 1338... Line 1408...
1338
 
1408
 
1339
    return status;
1409
    return status;
Line 1340... Line 1410...
1340
}
1410
}
1341
 
1411
 
1342
cairo_status_t
1412
cairo_status_t
1343
_cairo_path_fixed_stroke_to_polygon (const cairo_path_fixed_t	*path,
1413
_cairo_path_fixed_stroke_dashed_to_polygon (const cairo_path_fixed_t	*path,
1344
				     const cairo_stroke_style_t	*stroke_style,
1414
					    const cairo_stroke_style_t	*stroke_style,
1345
				     const cairo_matrix_t	*ctm,
1415
					    const cairo_matrix_t	*ctm,
1346
				     const cairo_matrix_t	*ctm_inverse,
1416
					    const cairo_matrix_t	*ctm_inverse,
1347
				     double		 tolerance,
1417
					    double		 tolerance,
1348
				     cairo_polygon_t *polygon)
1418
					    cairo_polygon_t *polygon)
1349
{
1419
{
Line 1350... Line 1420...
1350
    cairo_stroker_t stroker;
1420
    cairo_stroker_t stroker;
1351
    cairo_status_t status;
1421
    cairo_status_t status;
-
 
1422
 
1352
 
1423
    status = _cairo_stroker_init (&stroker, path, stroke_style,
1353
    status = _cairo_stroker_init (&stroker, stroke_style,
1424
			          ctm, ctm_inverse, tolerance,
Line 1354... Line 1425...
1354
			          ctm, ctm_inverse, tolerance);
1425
				  polygon->limits, polygon->num_limits);
1355
    if (unlikely (status))
1426
    if (unlikely (status))
Line 1356... Line -...
1356
	return status;
-
 
1357
 
-
 
1358
    stroker.add_external_edge = _cairo_polygon_add_external_edge,
-
 
1359
    stroker.closure = polygon;
1427
	return status;
1360
 
-
 
1361
    if (polygon->num_limits)
1428
 
1362
	_cairo_stroker_limit (&stroker, polygon->limits, polygon->num_limits);
1429
    stroker.add_external_edge = _cairo_polygon_add_external_edge,
1363
 
1430
    stroker.closure = polygon;
1364
    status = _cairo_path_fixed_interpret (path,
1431
 
1365
					  CAIRO_DIRECTION_FORWARD,
1432
    status = _cairo_path_fixed_interpret (path,
Line 1381... Line 1448...
1381
    _cairo_stroker_fini (&stroker);
1448
    _cairo_stroker_fini (&stroker);
Line 1382... Line 1449...
1382
 
1449
 
1383
    return status;
1450
    return status;
Line 1384... Line 1451...
1384
}
1451
}
1385
 
1452
 
1386
cairo_status_t
1453
cairo_int_status_t
1387
_cairo_path_fixed_stroke_to_traps (const cairo_path_fixed_t	*path,
1454
_cairo_path_fixed_stroke_polygon_to_traps (const cairo_path_fixed_t	*path,
1388
				   const cairo_stroke_style_t	*stroke_style,
1455
                                           const cairo_stroke_style_t	*stroke_style,
1389
				   const cairo_matrix_t	*ctm,
1456
                                           const cairo_matrix_t	*ctm,
1390
				   const cairo_matrix_t	*ctm_inverse,
1457
                                           const cairo_matrix_t	*ctm_inverse,
1391
				   double		 tolerance,
1458
                                           double		 tolerance,
1392
				   cairo_traps_t	*traps)
1459
                                           cairo_traps_t	*traps)
1393
{
1460
{
Line 1394... Line -...
1394
    cairo_status_t status;
-
 
1395
    cairo_polygon_t polygon;
-
 
1396
 
-
 
1397
    /* Before we do anything else, we attempt the rectilinear
-
 
1398
     * stroker. It's careful to generate trapezoids that align to
-
 
1399
     * device-pixel boundaries when possible. Many backends can render
-
 
1400
     * those much faster than non-aligned trapezoids, (by using clip
-
 
1401
     * regions, etc.) */
-
 
1402
    if (path->is_rectilinear) {
-
 
1403
	status = _cairo_path_fixed_stroke_rectilinear_to_traps (path,
-
 
1404
								stroke_style,
-
 
1405
								ctm,
-
 
1406
								traps);
-
 
1407
	if (status != CAIRO_INT_STATUS_UNSUPPORTED)
-
 
1408
	    return status;
-
 
1409
    }
-
 
1410
 
1461
    cairo_int_status_t status;
1411
    _cairo_polygon_init (&polygon);
-
 
1412
    if (traps->num_limits)
1462
    cairo_polygon_t polygon;
1413
	_cairo_polygon_limit (&polygon, traps->limits, traps->num_limits);
1463
 
1414
 
1464
    _cairo_polygon_init (&polygon, traps->limits, traps->num_limits);
1415
    status = _cairo_path_fixed_stroke_to_polygon (path,
1465
    status = _cairo_path_fixed_stroke_to_polygon (path,
1416
						  stroke_style,
1466
						  stroke_style,
Line 1431... Line 1481...
1431
BAIL:
1481
BAIL:
1432
    _cairo_polygon_fini (&polygon);
1482
    _cairo_polygon_fini (&polygon);
Line 1433... Line 1483...
1433
 
1483
 
1434
    return status;
1484
    return status;
1435
}
-
 
1436
 
-
 
1437
typedef struct _segment_t {
-
 
1438
    cairo_point_t p1, p2;
-
 
1439
    cairo_bool_t is_horizontal;
-
 
1440
    cairo_bool_t has_join;
-
 
1441
} segment_t;
-
 
1442
 
-
 
1443
typedef struct _cairo_rectilinear_stroker {
-
 
1444
    const cairo_stroke_style_t *stroke_style;
-
 
1445
    const cairo_matrix_t *ctm;
-
 
1446
 
-
 
1447
    cairo_fixed_t half_line_width;
-
 
1448
    cairo_bool_t do_traps;
-
 
1449
    void *container;
-
 
1450
    cairo_point_t current_point;
-
 
1451
    cairo_point_t first_point;
-
 
1452
    cairo_bool_t open_sub_path;
-
 
1453
 
-
 
1454
    cairo_stroker_dash_t dash;
-
 
1455
 
-
 
1456
    cairo_bool_t has_bounds;
-
 
1457
    cairo_box_t bounds;
-
 
1458
 
-
 
1459
    int num_segments;
-
 
1460
    int segments_size;
-
 
1461
    segment_t *segments;
-
 
1462
    segment_t segments_embedded[8]; /* common case is a single rectangle */
-
 
1463
} cairo_rectilinear_stroker_t;
-
 
1464
 
-
 
1465
static void
-
 
1466
_cairo_rectilinear_stroker_limit (cairo_rectilinear_stroker_t *stroker,
-
 
1467
				  const cairo_box_t *boxes,
-
 
1468
				  int num_boxes)
-
 
1469
{
-
 
1470
    stroker->has_bounds = TRUE;
-
 
1471
    _cairo_boxes_get_extents (boxes, num_boxes, &stroker->bounds);
-
 
1472
 
-
 
1473
    stroker->bounds.p1.x -= stroker->half_line_width;
-
 
1474
    stroker->bounds.p2.x += stroker->half_line_width;
-
 
1475
 
-
 
1476
    stroker->bounds.p1.y -= stroker->half_line_width;
-
 
1477
    stroker->bounds.p2.y += stroker->half_line_width;
-
 
1478
}
-
 
1479
 
-
 
1480
static cairo_bool_t
-
 
1481
_cairo_rectilinear_stroker_init (cairo_rectilinear_stroker_t	*stroker,
-
 
1482
				 const cairo_stroke_style_t	*stroke_style,
-
 
1483
				 const cairo_matrix_t		*ctm,
-
 
1484
				 cairo_bool_t			 do_traps,
-
 
1485
				 void				*container)
-
 
1486
{
-
 
1487
    /* This special-case rectilinear stroker only supports
-
 
1488
     * miter-joined lines (not curves) and a translation-only matrix
-
 
1489
     * (though it could probably be extended to support a matrix with
-
 
1490
     * uniform, integer scaling).
-
 
1491
     *
-
 
1492
     * It also only supports horizontal and vertical line_to
-
 
1493
     * elements. But we don't catch that here, but instead return
-
 
1494
     * UNSUPPORTED from _cairo_rectilinear_stroker_line_to if any
-
 
1495
     * non-rectilinear line_to is encountered.
-
 
1496
     */
-
 
1497
    if (stroke_style->line_join	!= CAIRO_LINE_JOIN_MITER)
-
 
1498
	return FALSE;
-
 
1499
 
-
 
1500
    /* If the miter limit turns right angles into bevels, then we
-
 
1501
     * can't use this optimization. Remember, the ratio is
-
 
1502
     * 1/sin(ɸ/2). So the cutoff is 1/sin(π/4.0) or ⎷2,
-
 
1503
     * which we round for safety. */
-
 
1504
    if (stroke_style->miter_limit < M_SQRT2)
-
 
1505
	return FALSE;
-
 
1506
 
-
 
1507
    if (! (stroke_style->line_cap == CAIRO_LINE_CAP_BUTT ||
-
 
1508
	   stroke_style->line_cap == CAIRO_LINE_CAP_SQUARE))
-
 
1509
    {
-
 
1510
	return FALSE;
-
 
1511
    }
-
 
1512
 
-
 
1513
    if (! _cairo_matrix_has_unity_scale (ctm))
-
 
1514
	return FALSE;
-
 
1515
 
-
 
1516
    stroker->stroke_style = stroke_style;
-
 
1517
    stroker->ctm = ctm;
-
 
1518
 
-
 
1519
    stroker->half_line_width =
-
 
1520
	_cairo_fixed_from_double (stroke_style->line_width / 2.0);
-
 
1521
    stroker->open_sub_path = FALSE;
-
 
1522
    stroker->segments = stroker->segments_embedded;
-
 
1523
    stroker->segments_size = ARRAY_LENGTH (stroker->segments_embedded);
-
 
1524
    stroker->num_segments = 0;
-
 
1525
 
-
 
1526
    _cairo_stroker_dash_init (&stroker->dash, stroke_style);
-
 
1527
 
-
 
1528
    stroker->has_bounds = FALSE;
-
 
1529
 
-
 
1530
    stroker->do_traps = do_traps;
-
 
1531
    stroker->container = container;
-
 
1532
 
-
 
1533
    return TRUE;
-
 
1534
}
-
 
1535
 
-
 
1536
static void
-
 
1537
_cairo_rectilinear_stroker_fini (cairo_rectilinear_stroker_t	*stroker)
-
 
1538
{
-
 
1539
    if (stroker->segments != stroker->segments_embedded)
-
 
1540
	free (stroker->segments);
-
 
1541
}
-
 
1542
 
-
 
1543
static cairo_status_t
-
 
1544
_cairo_rectilinear_stroker_add_segment (cairo_rectilinear_stroker_t *stroker,
-
 
1545
					const cairo_point_t	*p1,
-
 
1546
					const cairo_point_t	*p2,
-
 
1547
					cairo_bool_t		 is_horizontal,
-
 
1548
					cairo_bool_t		 has_join)
-
 
1549
{
-
 
1550
    if (CAIRO_INJECT_FAULT ())
-
 
1551
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
 
1552
 
-
 
1553
    if (stroker->num_segments == stroker->segments_size) {
-
 
1554
	int new_size = stroker->segments_size * 2;
-
 
1555
	segment_t *new_segments;
-
 
1556
 
-
 
1557
	if (stroker->segments == stroker->segments_embedded) {
-
 
1558
	    new_segments = _cairo_malloc_ab (new_size, sizeof (segment_t));
-
 
1559
	    if (unlikely (new_segments == NULL))
-
 
1560
		return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
 
1561
 
-
 
1562
	    memcpy (new_segments, stroker->segments,
-
 
1563
		    stroker->num_segments * sizeof (segment_t));
-
 
1564
	} else {
-
 
1565
	    new_segments = _cairo_realloc_ab (stroker->segments,
-
 
1566
					      new_size, sizeof (segment_t));
-
 
1567
	    if (unlikely (new_segments == NULL))
-
 
1568
		return _cairo_error (CAIRO_STATUS_NO_MEMORY);
-
 
1569
	}
-
 
1570
 
-
 
1571
	stroker->segments_size = new_size;
-
 
1572
	stroker->segments = new_segments;
-
 
1573
    }
-
 
1574
 
-
 
1575
    stroker->segments[stroker->num_segments].p1 = *p1;
-
 
1576
    stroker->segments[stroker->num_segments].p2 = *p2;
-
 
1577
    stroker->segments[stroker->num_segments].has_join = has_join;
-
 
1578
    stroker->segments[stroker->num_segments].is_horizontal = is_horizontal;
-
 
1579
    stroker->num_segments++;
-
 
1580
 
-
 
1581
    return CAIRO_STATUS_SUCCESS;
-
 
1582
}
-
 
1583
 
-
 
1584
static cairo_status_t
-
 
1585
_cairo_rectilinear_stroker_emit_segments (cairo_rectilinear_stroker_t *stroker)
-
 
1586
{
-
 
1587
    cairo_status_t status;
-
 
1588
    cairo_line_cap_t line_cap = stroker->stroke_style->line_cap;
-
 
1589
    cairo_fixed_t half_line_width = stroker->half_line_width;
-
 
1590
    int i;
-
 
1591
 
-
 
1592
    for (i = 0; i < stroker->num_segments; i++) {
-
 
1593
	cairo_point_t *a, *b;
-
 
1594
	cairo_bool_t lengthen_initial, shorten_final, lengthen_final;
-
 
1595
 
-
 
1596
	a = &stroker->segments[i].p1;
-
 
1597
	b = &stroker->segments[i].p2;
-
 
1598
 
-
 
1599
	/* For each segment we generate a single rectangular
-
 
1600
	 * trapezoid. This rectangle is based on a perpendicular
-
 
1601
	 * extension (by half the line width) of the segment endpoints
-
 
1602
	 * after some adjustments of the endpoints to account for caps
-
 
1603
	 * and joins.
-
 
1604
	 */
-
 
1605
 
-
 
1606
	/* We adjust the initial point of the segment to extend the
-
 
1607
	 * rectangle to include the previous cap or join, (this
-
 
1608
	 * adjustment applies to all segments except for the first
-
 
1609
	 * segment of open, butt-capped paths).
-
 
1610
	 */
-
 
1611
	lengthen_initial = TRUE;
-
 
1612
	if (i == 0 && stroker->open_sub_path && line_cap == CAIRO_LINE_CAP_BUTT)
-
 
1613
	    lengthen_initial = FALSE;
-
 
1614
 
-
 
1615
	/* The adjustment of the final point is trickier. For all but
-
 
1616
	 * the last segment we shorten the segment at the final
-
 
1617
	 * endpoint to not overlap with the subsequent join. For the
-
 
1618
	 * last segment we do the same shortening if the path is
-
 
1619
	 * closed. If the path is open and butt-capped we do no
-
 
1620
	 * adjustment, while if it's open and square-capped we do a
-
 
1621
	 * lengthening adjustment instead to include the cap.
-
 
1622
	 */
-
 
1623
	shorten_final = TRUE;
-
 
1624
	lengthen_final = FALSE;
-
 
1625
	if (i == stroker->num_segments - 1 && stroker->open_sub_path) {
-
 
1626
	    shorten_final = FALSE;
-
 
1627
	    if (line_cap == CAIRO_LINE_CAP_SQUARE)
-
 
1628
		lengthen_final = TRUE;
-
 
1629
	}
-
 
1630
 
-
 
1631
	/* Perform the adjustments of the endpoints. */
-
 
1632
	if (a->y == b->y) {
-
 
1633
	    if (a->x < b->x) {
-
 
1634
		if (lengthen_initial)
-
 
1635
		    a->x -= half_line_width;
-
 
1636
		if (shorten_final)
-
 
1637
		    b->x -= half_line_width;
-
 
1638
		else if (lengthen_final)
-
 
1639
		    b->x += half_line_width;
-
 
1640
	    } else {
-
 
1641
		if (lengthen_initial)
-
 
1642
		    a->x += half_line_width;
-
 
1643
		if (shorten_final)
-
 
1644
		    b->x += half_line_width;
-
 
1645
		else if (lengthen_final)
-
 
1646
		    b->x -= half_line_width;
-
 
1647
	    }
-
 
1648
 
-
 
1649
	    if (a->x > b->x) {
-
 
1650
		cairo_point_t *t;
-
 
1651
 
-
 
1652
		t = a;
-
 
1653
		a = b;
-
 
1654
		b = t;
-
 
1655
	    }
-
 
1656
	} else {
-
 
1657
	    if (a->y < b->y) {
-
 
1658
		if (lengthen_initial)
-
 
1659
		    a->y -= half_line_width;
-
 
1660
		if (shorten_final)
-
 
1661
		    b->y -= half_line_width;
-
 
1662
		else if (lengthen_final)
-
 
1663
		    b->y += half_line_width;
-
 
1664
	    } else {
-
 
1665
		if (lengthen_initial)
-
 
1666
		    a->y += half_line_width;
-
 
1667
		if (shorten_final)
-
 
1668
		    b->y += half_line_width;
-
 
1669
		else if (lengthen_final)
-
 
1670
		    b->y -= half_line_width;
-
 
1671
	    }
-
 
1672
 
-
 
1673
	    if (a->y > b->y) {
-
 
1674
		cairo_point_t *t;
-
 
1675
 
-
 
1676
		t = a;
-
 
1677
		a = b;
-
 
1678
		b = t;
-
 
1679
	    }
-
 
1680
	}
-
 
1681
 
-
 
1682
	/* Form the rectangle by expanding by half the line width in
-
 
1683
	 * either perpendicular direction. */
-
 
1684
	if (a->y == b->y) {
-
 
1685
	    a->y -= half_line_width;
-
 
1686
	    b->y += half_line_width;
-
 
1687
	} else {
-
 
1688
	    a->x -= half_line_width;
-
 
1689
	    b->x += half_line_width;
-
 
1690
	}
-
 
1691
 
-
 
1692
	if (stroker->do_traps) {
-
 
1693
	    status = _cairo_traps_tessellate_rectangle (stroker->container, a, b);
-
 
1694
	} else {
-
 
1695
	    cairo_box_t box;
-
 
1696
 
-
 
1697
	    box.p1 = *a;
-
 
1698
	    box.p2 = *b;
-
 
1699
 
-
 
1700
	    status = _cairo_boxes_add (stroker->container, &box);
-
 
1701
	}
-
 
1702
	if (unlikely (status))
-
 
1703
	    return status;
-
 
1704
    }
-
 
1705
 
-
 
1706
    stroker->num_segments = 0;
-
 
1707
 
-
 
1708
    return CAIRO_STATUS_SUCCESS;
-
 
1709
}
-
 
1710
 
-
 
1711
static cairo_status_t
-
 
1712
_cairo_rectilinear_stroker_emit_segments_dashed (cairo_rectilinear_stroker_t *stroker)
-
 
1713
{
-
 
1714
    cairo_status_t status;
-
 
1715
    cairo_line_cap_t line_cap = stroker->stroke_style->line_cap;
-
 
1716
    cairo_fixed_t half_line_width = stroker->half_line_width;
-
 
1717
    int i;
-
 
1718
 
-
 
1719
    for (i = 0; i < stroker->num_segments; i++) {
-
 
1720
	cairo_point_t *a, *b;
-
 
1721
	cairo_bool_t is_horizontal;
-
 
1722
 
-
 
1723
	a = &stroker->segments[i].p1;
-
 
1724
	b = &stroker->segments[i].p2;
-
 
1725
 
-
 
1726
	is_horizontal = stroker->segments[i].is_horizontal;
-
 
1727
 
-
 
1728
	/* Handle the joins for a potentially degenerate segment. */
-
 
1729
	if (line_cap == CAIRO_LINE_CAP_BUTT &&
-
 
1730
	    stroker->segments[i].has_join &&
-
 
1731
	    (i != stroker->num_segments - 1 ||
-
 
1732
	     (! stroker->open_sub_path && stroker->dash.dash_starts_on)))
-
 
1733
	{
-
 
1734
	    cairo_point_t p1 = stroker->segments[i].p1;
-
 
1735
	    cairo_point_t p2 = stroker->segments[i].p2;
-
 
1736
	    cairo_slope_t out_slope;
-
 
1737
	    int j = (i + 1) % stroker->num_segments;
-
 
1738
 
-
 
1739
	    _cairo_slope_init (&out_slope,
-
 
1740
			       &stroker->segments[j].p1,
-
 
1741
			       &stroker->segments[j].p2);
-
 
1742
 
-
 
1743
	    if (is_horizontal) {
-
 
1744
		if (p1.x <= p2.x) {
-
 
1745
		    p1.x = p2.x;
-
 
1746
		    p2.x += half_line_width;
-
 
1747
		} else {
-
 
1748
		    p1.x = p2.x - half_line_width;
-
 
1749
		}
-
 
1750
		if (out_slope.dy >= 0)
-
 
1751
		    p1.y -= half_line_width;
-
 
1752
		if (out_slope.dy <= 0)
-
 
1753
		    p2.y += half_line_width;
-
 
1754
	    } else {
-
 
1755
		if (p1.y <= p2.y) {
-
 
1756
		    p1.y = p2.y;
-
 
1757
		    p2.y += half_line_width;
-
 
1758
		} else {
-
 
1759
		    p1.y = p2.y - half_line_width;
-
 
1760
		}
-
 
1761
		if (out_slope.dx >= 0)
-
 
1762
		    p1.x -= half_line_width;
-
 
1763
		if (out_slope.dx <= 0)
-
 
1764
		    p2.x += half_line_width;
-
 
1765
	    }
-
 
1766
 
-
 
1767
	    if (stroker->do_traps) {
-
 
1768
		status = _cairo_traps_tessellate_rectangle (stroker->container, &p1, &p2);
-
 
1769
	    } else {
-
 
1770
		cairo_box_t box;
-
 
1771
 
-
 
1772
		box.p1 = p1;
-
 
1773
		box.p2 = p2;
-
 
1774
 
-
 
1775
		status = _cairo_boxes_add (stroker->container, &box);
-
 
1776
	    }
-
 
1777
	    if (unlikely (status))
-
 
1778
		return status;
-
 
1779
	}
-
 
1780
 
-
 
1781
	/* Perform the adjustments of the endpoints. */
-
 
1782
	if (is_horizontal) {
-
 
1783
	    if (line_cap == CAIRO_LINE_CAP_SQUARE) {
-
 
1784
		if (a->x <= b->x) {
-
 
1785
		    a->x -= half_line_width;
-
 
1786
		    b->x += half_line_width;
-
 
1787
		} else {
-
 
1788
		    a->x += half_line_width;
-
 
1789
		    b->x -= half_line_width;
-
 
1790
		}
-
 
1791
	    }
-
 
1792
 
-
 
1793
	    if (a->x > b->x) {
-
 
1794
		cairo_point_t *t;
-
 
1795
 
-
 
1796
		t = a;
-
 
1797
		a = b;
-
 
1798
		b = t;
-
 
1799
	    }
-
 
1800
 
-
 
1801
	    a->y -= half_line_width;
-
 
1802
	    b->y += half_line_width;
-
 
1803
	} else {
-
 
1804
	    if (line_cap == CAIRO_LINE_CAP_SQUARE) {
-
 
1805
		if (a->y <= b->y) {
-
 
1806
		    a->y -= half_line_width;
-
 
1807
		    b->y += half_line_width;
-
 
1808
		} else {
-
 
1809
		    a->y += half_line_width;
-
 
1810
		    b->y -= half_line_width;
-
 
1811
		}
-
 
1812
	    }
-
 
1813
 
-
 
1814
	    if (a->y > b->y) {
-
 
1815
		cairo_point_t *t;
-
 
1816
 
-
 
1817
		t = a;
-
 
1818
		a = b;
-
 
1819
		b = t;
-
 
1820
	    }
-
 
1821
 
-
 
1822
	    a->x -= half_line_width;
-
 
1823
	    b->x += half_line_width;
-
 
1824
	}
-
 
1825
 
-
 
1826
	if (a->x == b->x && a->y == b->y)
-
 
1827
	    continue;
-
 
1828
 
-
 
1829
	if (stroker->do_traps) {
-
 
1830
	    status = _cairo_traps_tessellate_rectangle (stroker->container, a, b);
-
 
1831
	} else {
-
 
1832
	    cairo_box_t box;
-
 
1833
 
-
 
1834
	    box.p1 = *a;
-
 
1835
	    box.p2 = *b;
-
 
1836
 
-
 
1837
	    status = _cairo_boxes_add (stroker->container, &box);
-
 
1838
	}
-
 
1839
	if (unlikely (status))
-
 
1840
	    return status;
-
 
1841
    }
-
 
1842
 
-
 
1843
    stroker->num_segments = 0;
-
 
1844
 
-
 
1845
    return CAIRO_STATUS_SUCCESS;
-
 
1846
}
-
 
1847
 
-
 
1848
static cairo_status_t
-
 
1849
_cairo_rectilinear_stroker_move_to (void		*closure,
-
 
1850
				    const cairo_point_t	*point)
-
 
1851
{
-
 
1852
    cairo_rectilinear_stroker_t *stroker = closure;
-
 
1853
    cairo_status_t status;
-
 
1854
 
-
 
1855
    if (stroker->dash.dashed)
-
 
1856
	status = _cairo_rectilinear_stroker_emit_segments_dashed (stroker);
-
 
1857
    else
-
 
1858
	status = _cairo_rectilinear_stroker_emit_segments (stroker);
-
 
1859
    if (unlikely (status))
-
 
1860
	return status;
-
 
1861
 
-
 
1862
    /* reset the dash pattern for new sub paths */
-
 
1863
    _cairo_stroker_dash_start (&stroker->dash);
-
 
1864
 
-
 
1865
    stroker->current_point = *point;
-
 
1866
    stroker->first_point = *point;
-
 
1867
 
-
 
1868
    return CAIRO_STATUS_SUCCESS;
-
 
1869
}
-
 
1870
 
-
 
1871
static cairo_status_t
-
 
1872
_cairo_rectilinear_stroker_line_to (void		*closure,
-
 
1873
				    const cairo_point_t	*b)
-
 
1874
{
-
 
1875
    cairo_rectilinear_stroker_t *stroker = closure;
-
 
1876
    cairo_point_t *a = &stroker->current_point;
-
 
1877
    cairo_status_t status;
-
 
1878
 
-
 
1879
    /* We only support horizontal or vertical elements. */
-
 
1880
    assert (a->x == b->x || a->y == b->y);
-
 
1881
 
-
 
1882
    /* We don't draw anything for degenerate paths. */
-
 
1883
    if (a->x == b->x && a->y == b->y)
-
 
1884
	return CAIRO_STATUS_SUCCESS;
-
 
1885
 
-
 
1886
    status = _cairo_rectilinear_stroker_add_segment (stroker, a, b,
-
 
1887
						     a->y == b->y,
-
 
1888
						     TRUE);
-
 
1889
 
-
 
1890
    stroker->current_point = *b;
-
 
1891
    stroker->open_sub_path = TRUE;
-
 
1892
 
-
 
1893
    return status;
-
 
1894
}
-
 
1895
 
-
 
1896
static cairo_status_t
-
 
1897
_cairo_rectilinear_stroker_line_to_dashed (void		*closure,
-
 
1898
					   const cairo_point_t	*point)
-
 
1899
{
-
 
1900
    cairo_rectilinear_stroker_t *stroker = closure;
-
 
1901
    const cairo_point_t *a = &stroker->current_point;
-
 
1902
    const cairo_point_t *b = point;
-
 
1903
    cairo_bool_t fully_in_bounds;
-
 
1904
    double sign, remain;
-
 
1905
    cairo_fixed_t mag;
-
 
1906
    cairo_status_t status;
-
 
1907
    cairo_line_t segment;
-
 
1908
    cairo_bool_t dash_on = FALSE;
-
 
1909
    cairo_bool_t is_horizontal;
-
 
1910
 
-
 
1911
    /* We don't draw anything for degenerate paths. */
-
 
1912
    if (a->x == b->x && a->y == b->y)
-
 
1913
	return CAIRO_STATUS_SUCCESS;
-
 
1914
 
-
 
1915
    /* We only support horizontal or vertical elements. */
-
 
1916
    assert (a->x == b->x || a->y == b->y);
-
 
1917
 
-
 
1918
    fully_in_bounds = TRUE;
-
 
1919
    if (stroker->has_bounds &&
-
 
1920
	(! _cairo_box_contains_point (&stroker->bounds, a) ||
-
 
1921
	 ! _cairo_box_contains_point (&stroker->bounds, b)))
-
 
1922
    {
-
 
1923
	fully_in_bounds = FALSE;
-
 
1924
    }
-
 
1925
 
-
 
1926
    is_horizontal = a->y == b->y;
-
 
1927
    if (is_horizontal)
-
 
1928
	mag = b->x - a->x;
-
 
1929
    else
-
 
1930
	mag = b->y - a->y;
-
 
1931
    if (mag < 0) {
-
 
1932
	remain = _cairo_fixed_to_double (-mag);
-
 
1933
	sign = 1.;
-
 
1934
    } else {
-
 
1935
	remain = _cairo_fixed_to_double (mag);
-
 
1936
	sign = -1.;
-
 
1937
    }
-
 
1938
 
-
 
1939
    segment.p2 = segment.p1 = *a;
-
 
1940
    while (remain > 0.) {
-
 
1941
	double step_length;
-
 
1942
 
-
 
1943
	step_length = MIN (stroker->dash.dash_remain, remain);
-
 
1944
	remain -= step_length;
-
 
1945
 
-
 
1946
	mag = _cairo_fixed_from_double (sign*remain);
-
 
1947
	if (is_horizontal)
-
 
1948
	    segment.p2.x = b->x + mag;
-
 
1949
	else
-
 
1950
	    segment.p2.y = b->y + mag;
-
 
1951
 
-
 
1952
	if (stroker->dash.dash_on &&
-
 
1953
	    (fully_in_bounds ||
-
 
1954
	     _cairo_box_intersects_line_segment (&stroker->bounds, &segment)))
-
 
1955
	{
-
 
1956
	    status = _cairo_rectilinear_stroker_add_segment (stroker,
-
 
1957
							     &segment.p1,
-
 
1958
							     &segment.p2,
-
 
1959
							     is_horizontal,
-
 
1960
							     remain <= 0.);
-
 
1961
	    if (unlikely (status))
-
 
1962
		return status;
-
 
1963
 
-
 
1964
	    dash_on = TRUE;
-
 
1965
	}
-
 
1966
	else
-
 
1967
	{
-
 
1968
	    dash_on = FALSE;
-
 
1969
	}
-
 
1970
 
-
 
1971
	_cairo_stroker_dash_step (&stroker->dash, step_length);
-
 
1972
	segment.p1 = segment.p2;
-
 
1973
    }
-
 
1974
 
-
 
1975
    if (stroker->dash.dash_on && ! dash_on &&
-
 
1976
	(fully_in_bounds ||
-
 
1977
	 _cairo_box_intersects_line_segment (&stroker->bounds, &segment)))
-
 
1978
    {
-
 
1979
 
-
 
1980
	/* This segment ends on a transition to dash_on, compute a new face
-
 
1981
	 * and add cap for the beginning of the next dash_on step.
-
 
1982
	 */
-
 
1983
 
-
 
1984
	status = _cairo_rectilinear_stroker_add_segment (stroker,
-
 
1985
							 &segment.p1,
-
 
1986
							 &segment.p1,
-
 
1987
							 is_horizontal,
-
 
1988
							 TRUE);
-
 
1989
	if (unlikely (status))
-
 
1990
	    return status;
-
 
1991
    }
-
 
1992
 
-
 
1993
    stroker->current_point = *point;
-
 
1994
    stroker->open_sub_path = TRUE;
-
 
1995
 
-
 
1996
    return CAIRO_STATUS_SUCCESS;
-
 
1997
}
-
 
1998
 
-
 
1999
static cairo_status_t
-
 
2000
_cairo_rectilinear_stroker_close_path (void *closure)
-
 
2001
{
-
 
2002
    cairo_rectilinear_stroker_t *stroker = closure;
-
 
2003
    cairo_status_t status;
-
 
2004
 
-
 
2005
    /* We don't draw anything for degenerate paths. */
-
 
2006
    if (! stroker->open_sub_path)
-
 
2007
	return CAIRO_STATUS_SUCCESS;
-
 
2008
 
-
 
2009
    if (stroker->dash.dashed) {
-
 
2010
	status = _cairo_rectilinear_stroker_line_to_dashed (stroker,
-
 
2011
							    &stroker->first_point);
-
 
2012
    } else {
-
 
2013
	status = _cairo_rectilinear_stroker_line_to (stroker,
-
 
2014
						     &stroker->first_point);
-
 
2015
    }
-
 
2016
    if (unlikely (status))
-
 
2017
	return status;
-
 
2018
 
-
 
2019
    stroker->open_sub_path = FALSE;
-
 
2020
 
-
 
2021
    if (stroker->dash.dashed)
-
 
2022
	status = _cairo_rectilinear_stroker_emit_segments_dashed (stroker);
-
 
2023
    else
-
 
2024
	status = _cairo_rectilinear_stroker_emit_segments (stroker);
-
 
2025
    if (unlikely (status))
-
 
2026
	return status;
-
 
2027
 
-
 
2028
    return CAIRO_STATUS_SUCCESS;
-
 
2029
}
-
 
2030
 
-
 
2031
cairo_int_status_t
-
 
2032
_cairo_path_fixed_stroke_rectilinear_to_traps (const cairo_path_fixed_t	*path,
-
 
2033
					       const cairo_stroke_style_t	*stroke_style,
-
 
2034
					       const cairo_matrix_t	*ctm,
-
 
2035
					       cairo_traps_t		*traps)
-
 
2036
{
-
 
2037
    cairo_rectilinear_stroker_t rectilinear_stroker;
-
 
2038
    cairo_int_status_t status;
-
 
2039
 
-
 
2040
    assert (path->is_rectilinear);
-
 
2041
 
-
 
2042
    if (! _cairo_rectilinear_stroker_init (&rectilinear_stroker,
-
 
2043
					   stroke_style, ctm,
-
 
2044
					   TRUE, traps))
-
 
2045
    {
-
 
2046
	return CAIRO_INT_STATUS_UNSUPPORTED;
-
 
2047
    }
-
 
2048
 
-
 
2049
    if (traps->num_limits) {
-
 
2050
	_cairo_rectilinear_stroker_limit (&rectilinear_stroker,
-
 
2051
					  traps->limits,
-
 
2052
					  traps->num_limits);
-
 
2053
    }
-
 
2054
 
-
 
2055
    status = _cairo_path_fixed_interpret (path,
-
 
2056
					  CAIRO_DIRECTION_FORWARD,
-
 
2057
					  _cairo_rectilinear_stroker_move_to,
-
 
2058
					  rectilinear_stroker.dash.dashed ?
-
 
2059
					  _cairo_rectilinear_stroker_line_to_dashed :
-
 
2060
					  _cairo_rectilinear_stroker_line_to,
-
 
2061
					  NULL,
-
 
2062
					  _cairo_rectilinear_stroker_close_path,
-
 
2063
					  &rectilinear_stroker);
-
 
2064
    if (unlikely (status))
-
 
2065
	goto BAIL;
-
 
2066
 
-
 
2067
    if (rectilinear_stroker.dash.dashed)
-
 
2068
	status = _cairo_rectilinear_stroker_emit_segments_dashed (&rectilinear_stroker);
-
 
2069
    else
-
 
2070
	status = _cairo_rectilinear_stroker_emit_segments (&rectilinear_stroker);
-
 
2071
 
-
 
2072
    traps->is_rectilinear = 1;
-
 
2073
    traps->is_rectangular = 1;
-
 
2074
    /* As we incrementally tessellate, we do not eliminate self-intersections */
-
 
2075
    traps->has_intersections = traps->num_traps > 1;
-
 
2076
BAIL:
-
 
2077
    _cairo_rectilinear_stroker_fini (&rectilinear_stroker);
-
 
2078
 
-
 
2079
    if (unlikely (status))
-
 
2080
	_cairo_traps_clear (traps);
-
 
2081
 
-
 
2082
    return status;
-
 
2083
}
-
 
2084
 
-
 
2085
cairo_int_status_t
-
 
2086
_cairo_path_fixed_stroke_rectilinear_to_boxes (const cairo_path_fixed_t	*path,
-
 
2087
					       const cairo_stroke_style_t	*stroke_style,
-
 
2088
					       const cairo_matrix_t	*ctm,
-
 
2089
					       cairo_boxes_t		*boxes)
-
 
2090
{
-
 
2091
    cairo_rectilinear_stroker_t rectilinear_stroker;
-
 
2092
    cairo_int_status_t status;
-
 
2093
 
-
 
2094
    assert (path->is_rectilinear);
-
 
2095
 
-
 
2096
    if (! _cairo_rectilinear_stroker_init (&rectilinear_stroker,
-
 
2097
					   stroke_style, ctm,
-
 
2098
					   FALSE, boxes))
-
 
2099
    {
-
 
2100
	return CAIRO_INT_STATUS_UNSUPPORTED;
-
 
2101
    }
-
 
2102
 
-
 
2103
    if (boxes->num_limits) {
-
 
2104
	_cairo_rectilinear_stroker_limit (&rectilinear_stroker,
-
 
2105
					  boxes->limits,
-
 
2106
					  boxes->num_limits);
-
 
2107
    }
-
 
2108
 
-
 
2109
    status = _cairo_path_fixed_interpret (path,
-
 
2110
					  CAIRO_DIRECTION_FORWARD,
-
 
2111
					  _cairo_rectilinear_stroker_move_to,
-
 
2112
					  rectilinear_stroker.dash.dashed ?
-
 
2113
					  _cairo_rectilinear_stroker_line_to_dashed :
-
 
2114
					  _cairo_rectilinear_stroker_line_to,
-
 
2115
					  NULL,
-
 
2116
					  _cairo_rectilinear_stroker_close_path,
-
 
2117
					  &rectilinear_stroker);
-
 
2118
    if (unlikely (status))
-
 
2119
	goto BAIL;
-
 
2120
 
-
 
2121
    if (rectilinear_stroker.dash.dashed)
-
 
2122
	status = _cairo_rectilinear_stroker_emit_segments_dashed (&rectilinear_stroker);
-
 
2123
    else
-
 
2124
	status = _cairo_rectilinear_stroker_emit_segments (&rectilinear_stroker);
-
 
2125
    if (unlikely (status))
-
 
2126
	goto BAIL;
-
 
2127
 
-
 
2128
    /* As we incrementally tessellate, we do not eliminate self-intersections */
-
 
2129
    status = _cairo_bentley_ottmann_tessellate_boxes (boxes,
-
 
2130
						      CAIRO_FILL_RULE_WINDING,
-
 
2131
						      boxes);
-
 
2132
    if (unlikely (status))
-
 
2133
	goto BAIL;
-
 
2134
 
-
 
2135
    _cairo_rectilinear_stroker_fini (&rectilinear_stroker);
-
 
2136
 
-
 
2137
    return CAIRO_STATUS_SUCCESS;
-
 
2138
 
-
 
2139
BAIL:
-
 
2140
    _cairo_rectilinear_stroker_fini (&rectilinear_stroker);
-
 
2141
    _cairo_boxes_clear (boxes);
-
 
2142
    return status;
-