1 /* -*- Mode: c; tab-width: 8; c-basic-offset: 4; indent-tabs-mode: t; -*- */
2 /* cairo - a vector graphics library with display and print output
4 * Copyright © 2002 University of Southern California
5 * Copyright © 2005 Red Hat, Inc.
7 * This library is free software; you can redistribute it and/or
8 * modify it either under the terms of the GNU Lesser General Public
9 * License version 2.1 as published by the Free Software Foundation
10 * (the "LGPL") or, at your option, under the terms of the Mozilla
11 * Public License Version 1.1 (the "MPL"). If you do not alter this
12 * notice, a recipient may use your version of this file under either
13 * the MPL or the LGPL.
15 * You should have received a copy of the LGPL along with this library
16 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
18 * You should have received a copy of the MPL along with this library
19 * in the file COPYING-MPL-1.1
21 * The contents of this file are subject to the Mozilla Public License
22 * Version 1.1 (the "License"); you may not use this file except in
23 * compliance with the License. You may obtain a copy of the License at
24 * http://www.mozilla.org/MPL/
26 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
27 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
28 * the specific language governing rights and limitations.
30 * The Original Code is the cairo graphics library.
32 * The Initial Developer of the Original Code is University of Southern
36 * Carl D. Worth <cworth@cworth.org>
41 #include "cairo-box-inline.h"
42 #include "cairo-error-private.h"
43 #include "cairo-list-inline.h"
44 #include "cairo-path-fixed-private.h"
45 #include "cairo-slope-private.h"
48 _cairo_path_fixed_add (cairo_path_fixed_t
*path
,
50 const cairo_point_t
*points
,
54 _cairo_path_fixed_add_buf (cairo_path_fixed_t
*path
,
55 cairo_path_buf_t
*buf
);
57 static cairo_path_buf_t
*
58 _cairo_path_buf_create (int size_ops
, int size_points
);
61 _cairo_path_buf_destroy (cairo_path_buf_t
*buf
);
64 _cairo_path_buf_add_op (cairo_path_buf_t
*buf
,
68 _cairo_path_buf_add_points (cairo_path_buf_t
*buf
,
69 const cairo_point_t
*points
,
73 _cairo_path_fixed_init (cairo_path_fixed_t
*path
)
75 VG (VALGRIND_MAKE_MEM_UNDEFINED (path
, sizeof (cairo_path_fixed_t
)));
77 cairo_list_init (&path
->buf
.base
.link
);
79 path
->buf
.base
.num_ops
= 0;
80 path
->buf
.base
.num_points
= 0;
81 path
->buf
.base
.size_ops
= ARRAY_LENGTH (path
->buf
.op
);
82 path
->buf
.base
.size_points
= ARRAY_LENGTH (path
->buf
.points
);
83 path
->buf
.base
.op
= path
->buf
.op
;
84 path
->buf
.base
.points
= path
->buf
.points
;
86 path
->current_point
.x
= 0;
87 path
->current_point
.y
= 0;
88 path
->last_move_point
= path
->current_point
;
90 path
->has_current_point
= FALSE
;
91 path
->needs_move_to
= TRUE
;
92 path
->has_extents
= FALSE
;
93 path
->has_curve_to
= FALSE
;
94 path
->stroke_is_rectilinear
= TRUE
;
95 path
->fill_is_rectilinear
= TRUE
;
96 path
->fill_maybe_region
= TRUE
;
97 path
->fill_is_empty
= TRUE
;
99 path
->extents
.p1
.x
= path
->extents
.p1
.y
= 0;
100 path
->extents
.p2
.x
= path
->extents
.p2
.y
= 0;
104 _cairo_path_fixed_init_copy (cairo_path_fixed_t
*path
,
105 const cairo_path_fixed_t
*other
)
107 cairo_path_buf_t
*buf
, *other_buf
;
108 unsigned int num_points
, num_ops
;
110 VG (VALGRIND_MAKE_MEM_UNDEFINED (path
, sizeof (cairo_path_fixed_t
)));
112 cairo_list_init (&path
->buf
.base
.link
);
114 path
->buf
.base
.op
= path
->buf
.op
;
115 path
->buf
.base
.points
= path
->buf
.points
;
116 path
->buf
.base
.size_ops
= ARRAY_LENGTH (path
->buf
.op
);
117 path
->buf
.base
.size_points
= ARRAY_LENGTH (path
->buf
.points
);
119 path
->current_point
= other
->current_point
;
120 path
->last_move_point
= other
->last_move_point
;
122 path
->has_current_point
= other
->has_current_point
;
123 path
->needs_move_to
= other
->needs_move_to
;
124 path
->has_extents
= other
->has_extents
;
125 path
->has_curve_to
= other
->has_curve_to
;
126 path
->stroke_is_rectilinear
= other
->stroke_is_rectilinear
;
127 path
->fill_is_rectilinear
= other
->fill_is_rectilinear
;
128 path
->fill_maybe_region
= other
->fill_maybe_region
;
129 path
->fill_is_empty
= other
->fill_is_empty
;
131 path
->extents
= other
->extents
;
133 path
->buf
.base
.num_ops
= other
->buf
.base
.num_ops
;
134 path
->buf
.base
.num_points
= other
->buf
.base
.num_points
;
135 memcpy (path
->buf
.op
, other
->buf
.base
.op
,
136 other
->buf
.base
.num_ops
* sizeof (other
->buf
.op
[0]));
137 memcpy (path
->buf
.points
, other
->buf
.points
,
138 other
->buf
.base
.num_points
* sizeof (other
->buf
.points
[0]));
140 num_points
= num_ops
= 0;
141 for (other_buf
= cairo_path_buf_next (cairo_path_head (other
));
142 other_buf
!= cairo_path_head (other
);
143 other_buf
= cairo_path_buf_next (other_buf
))
145 num_ops
+= other_buf
->num_ops
;
146 num_points
+= other_buf
->num_points
;
150 buf
= _cairo_path_buf_create (num_ops
, num_points
);
151 if (unlikely (buf
== NULL
)) {
152 _cairo_path_fixed_fini (path
);
153 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
156 for (other_buf
= cairo_path_buf_next (cairo_path_head (other
));
157 other_buf
!= cairo_path_head (other
);
158 other_buf
= cairo_path_buf_next (other_buf
))
160 memcpy (buf
->op
+ buf
->num_ops
, other_buf
->op
,
161 other_buf
->num_ops
* sizeof (buf
->op
[0]));
162 buf
->num_ops
+= other_buf
->num_ops
;
164 memcpy (buf
->points
+ buf
->num_points
, other_buf
->points
,
165 other_buf
->num_points
* sizeof (buf
->points
[0]));
166 buf
->num_points
+= other_buf
->num_points
;
169 _cairo_path_fixed_add_buf (path
, buf
);
172 return CAIRO_STATUS_SUCCESS
;
176 _cairo_path_fixed_hash (const cairo_path_fixed_t
*path
)
178 unsigned long hash
= _CAIRO_HASH_INIT_VALUE
;
179 const cairo_path_buf_t
*buf
;
183 cairo_path_foreach_buf_start (buf
, path
) {
184 hash
= _cairo_hash_bytes (hash
, buf
->op
,
185 buf
->num_ops
* sizeof (buf
->op
[0]));
186 count
+= buf
->num_ops
;
187 } cairo_path_foreach_buf_end (buf
, path
);
188 hash
= _cairo_hash_bytes (hash
, &count
, sizeof (count
));
191 cairo_path_foreach_buf_start (buf
, path
) {
192 hash
= _cairo_hash_bytes (hash
, buf
->points
,
193 buf
->num_points
* sizeof (buf
->points
[0]));
194 count
+= buf
->num_points
;
195 } cairo_path_foreach_buf_end (buf
, path
);
196 hash
= _cairo_hash_bytes (hash
, &count
, sizeof (count
));
202 _cairo_path_fixed_size (const cairo_path_fixed_t
*path
)
204 const cairo_path_buf_t
*buf
;
205 int num_points
, num_ops
;
207 num_ops
= num_points
= 0;
208 cairo_path_foreach_buf_start (buf
, path
) {
209 num_ops
+= buf
->num_ops
;
210 num_points
+= buf
->num_points
;
211 } cairo_path_foreach_buf_end (buf
, path
);
213 return num_ops
* sizeof (buf
->op
[0]) +
214 num_points
* sizeof (buf
->points
[0]);
218 _cairo_path_fixed_equal (const cairo_path_fixed_t
*a
,
219 const cairo_path_fixed_t
*b
)
221 const cairo_path_buf_t
*buf_a
, *buf_b
;
222 const cairo_path_op_t
*ops_a
, *ops_b
;
223 const cairo_point_t
*points_a
, *points_b
;
224 int num_points_a
, num_ops_a
;
225 int num_points_b
, num_ops_b
;
230 /* use the flags to quickly differentiate based on contents */
231 if (a
->has_curve_to
!= b
->has_curve_to
)
236 if (a
->extents
.p1
.x
!= b
->extents
.p1
.x
||
237 a
->extents
.p1
.y
!= b
->extents
.p1
.y
||
238 a
->extents
.p2
.x
!= b
->extents
.p2
.x
||
239 a
->extents
.p2
.y
!= b
->extents
.p2
.y
)
244 num_ops_a
= num_points_a
= 0;
245 cairo_path_foreach_buf_start (buf_a
, a
) {
246 num_ops_a
+= buf_a
->num_ops
;
247 num_points_a
+= buf_a
->num_points
;
248 } cairo_path_foreach_buf_end (buf_a
, a
);
250 num_ops_b
= num_points_b
= 0;
251 cairo_path_foreach_buf_start (buf_b
, b
) {
252 num_ops_b
+= buf_b
->num_ops
;
253 num_points_b
+= buf_b
->num_points
;
254 } cairo_path_foreach_buf_end (buf_b
, b
);
256 if (num_ops_a
== 0 && num_ops_b
== 0)
259 if (num_ops_a
!= num_ops_b
|| num_points_a
!= num_points_b
)
262 buf_a
= cairo_path_head (a
);
263 num_points_a
= buf_a
->num_points
;
264 num_ops_a
= buf_a
->num_ops
;
266 points_a
= buf_a
->points
;
268 buf_b
= cairo_path_head (b
);
269 num_points_b
= buf_b
->num_points
;
270 num_ops_b
= buf_b
->num_ops
;
272 points_b
= buf_b
->points
;
275 int num_ops
= MIN (num_ops_a
, num_ops_b
);
276 int num_points
= MIN (num_points_a
, num_points_b
);
278 if (memcmp (ops_a
, ops_b
, num_ops
* sizeof (cairo_path_op_t
)))
280 if (memcmp (points_a
, points_b
, num_points
* sizeof (cairo_point_t
)))
283 num_ops_a
-= num_ops
;
285 num_points_a
-= num_points
;
286 points_a
+= num_points
;
287 if (num_ops_a
== 0 || num_points_a
== 0) {
288 if (num_ops_a
|| num_points_a
)
291 buf_a
= cairo_path_buf_next (buf_a
);
292 if (buf_a
== cairo_path_head (a
))
295 num_points_a
= buf_a
->num_points
;
296 num_ops_a
= buf_a
->num_ops
;
298 points_a
= buf_a
->points
;
301 num_ops_b
-= num_ops
;
303 num_points_b
-= num_points
;
304 points_b
+= num_points
;
305 if (num_ops_b
== 0 || num_points_b
== 0) {
306 if (num_ops_b
|| num_points_b
)
309 buf_b
= cairo_path_buf_next (buf_b
);
310 if (buf_b
== cairo_path_head (b
))
313 num_points_b
= buf_b
->num_points
;
314 num_ops_b
= buf_b
->num_ops
;
316 points_b
= buf_b
->points
;
324 _cairo_path_fixed_create (void)
326 cairo_path_fixed_t
*path
;
328 path
= malloc (sizeof (cairo_path_fixed_t
));
330 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY
);
334 _cairo_path_fixed_init (path
);
339 _cairo_path_fixed_fini (cairo_path_fixed_t
*path
)
341 cairo_path_buf_t
*buf
;
343 buf
= cairo_path_buf_next (cairo_path_head (path
));
344 while (buf
!= cairo_path_head (path
)) {
345 cairo_path_buf_t
*this = buf
;
346 buf
= cairo_path_buf_next (buf
);
347 _cairo_path_buf_destroy (this);
350 VG (VALGRIND_MAKE_MEM_NOACCESS (path
, sizeof (cairo_path_fixed_t
)));
354 _cairo_path_fixed_destroy (cairo_path_fixed_t
*path
)
356 _cairo_path_fixed_fini (path
);
360 static cairo_path_op_t
361 _cairo_path_fixed_last_op (cairo_path_fixed_t
*path
)
363 cairo_path_buf_t
*buf
;
365 buf
= cairo_path_tail (path
);
366 assert (buf
->num_ops
!= 0);
368 return buf
->op
[buf
->num_ops
- 1];
371 static inline const cairo_point_t
*
372 _cairo_path_fixed_penultimate_point (cairo_path_fixed_t
*path
)
374 cairo_path_buf_t
*buf
;
376 buf
= cairo_path_tail (path
);
377 if (likely (buf
->num_points
>= 2)) {
378 return &buf
->points
[buf
->num_points
- 2];
380 cairo_path_buf_t
*prev_buf
= cairo_path_buf_prev (buf
);
382 assert (prev_buf
->num_points
>= 2 - buf
->num_points
);
383 return &prev_buf
->points
[prev_buf
->num_points
- (2 - buf
->num_points
)];
388 _cairo_path_fixed_drop_line_to (cairo_path_fixed_t
*path
)
390 cairo_path_buf_t
*buf
;
392 assert (_cairo_path_fixed_last_op (path
) == CAIRO_PATH_OP_LINE_TO
);
394 buf
= cairo_path_tail (path
);
400 _cairo_path_fixed_move_to (cairo_path_fixed_t
*path
,
404 _cairo_path_fixed_new_sub_path (path
);
406 path
->has_current_point
= TRUE
;
407 path
->current_point
.x
= x
;
408 path
->current_point
.y
= y
;
409 path
->last_move_point
= path
->current_point
;
411 return CAIRO_STATUS_SUCCESS
;
414 static cairo_status_t
415 _cairo_path_fixed_move_to_apply (cairo_path_fixed_t
*path
)
417 if (likely (! path
->needs_move_to
))
418 return CAIRO_STATUS_SUCCESS
;
420 path
->needs_move_to
= FALSE
;
422 if (path
->has_extents
) {
423 _cairo_box_add_point (&path
->extents
, &path
->current_point
);
425 _cairo_box_set (&path
->extents
, &path
->current_point
, &path
->current_point
);
426 path
->has_extents
= TRUE
;
429 if (path
->fill_maybe_region
) {
430 path
->fill_maybe_region
= _cairo_fixed_is_integer (path
->current_point
.x
) &&
431 _cairo_fixed_is_integer (path
->current_point
.y
);
434 path
->last_move_point
= path
->current_point
;
436 return _cairo_path_fixed_add (path
, CAIRO_PATH_OP_MOVE_TO
, &path
->current_point
, 1);
440 _cairo_path_fixed_new_sub_path (cairo_path_fixed_t
*path
)
442 if (! path
->needs_move_to
) {
443 /* If the current subpath doesn't need_move_to, it contains at least one command */
444 if (path
->fill_is_rectilinear
) {
445 /* Implicitly close for fill */
446 path
->fill_is_rectilinear
= path
->current_point
.x
== path
->last_move_point
.x
||
447 path
->current_point
.y
== path
->last_move_point
.y
;
448 path
->fill_maybe_region
&= path
->fill_is_rectilinear
;
450 path
->needs_move_to
= TRUE
;
453 path
->has_current_point
= FALSE
;
457 _cairo_path_fixed_rel_move_to (cairo_path_fixed_t
*path
,
461 if (unlikely (! path
->has_current_point
))
462 return _cairo_error (CAIRO_STATUS_NO_CURRENT_POINT
);
464 return _cairo_path_fixed_move_to (path
,
465 path
->current_point
.x
+ dx
,
466 path
->current_point
.y
+ dy
);
471 _cairo_path_fixed_line_to (cairo_path_fixed_t
*path
,
475 cairo_status_t status
;
481 /* When there is not yet a current point, the line_to operation
482 * becomes a move_to instead. Note: We have to do this by
483 * explicitly calling into _cairo_path_fixed_move_to to ensure
484 * that the last_move_point state is updated properly.
486 if (! path
->has_current_point
)
487 return _cairo_path_fixed_move_to (path
, point
.x
, point
.y
);
489 status
= _cairo_path_fixed_move_to_apply (path
);
490 if (unlikely (status
))
493 /* If the previous op was but the initial MOVE_TO and this segment
494 * is degenerate, then we can simply skip this point. Note that
495 * a move-to followed by a degenerate line-to is a valid path for
496 * stroking, but at all other times is simply a degenerate segment.
498 if (_cairo_path_fixed_last_op (path
) != CAIRO_PATH_OP_MOVE_TO
) {
499 if (x
== path
->current_point
.x
&& y
== path
->current_point
.y
)
500 return CAIRO_STATUS_SUCCESS
;
503 /* If the previous op was also a LINE_TO with the same gradient,
504 * then just change its end-point rather than adding a new op.
506 if (_cairo_path_fixed_last_op (path
) == CAIRO_PATH_OP_LINE_TO
) {
507 const cairo_point_t
*p
;
509 p
= _cairo_path_fixed_penultimate_point (path
);
510 if (p
->x
== path
->current_point
.x
&& p
->y
== path
->current_point
.y
) {
511 /* previous line element was degenerate, replace */
512 _cairo_path_fixed_drop_line_to (path
);
514 cairo_slope_t prev
, self
;
516 _cairo_slope_init (&prev
, p
, &path
->current_point
);
517 _cairo_slope_init (&self
, &path
->current_point
, &point
);
518 if (_cairo_slope_equal (&prev
, &self
) &&
519 /* cannot trim anti-parallel segments whilst stroking */
520 ! _cairo_slope_backwards (&prev
, &self
))
522 _cairo_path_fixed_drop_line_to (path
);
523 /* In this case the flags might be more restrictive than
524 * what we actually need.
525 * When changing the flags definition we should check if
526 * changing the line_to point can affect them.
532 if (path
->stroke_is_rectilinear
) {
533 path
->stroke_is_rectilinear
= path
->current_point
.x
== x
||
534 path
->current_point
.y
== y
;
535 path
->fill_is_rectilinear
&= path
->stroke_is_rectilinear
;
536 path
->fill_maybe_region
&= path
->fill_is_rectilinear
;
537 if (path
->fill_maybe_region
) {
538 path
->fill_maybe_region
= _cairo_fixed_is_integer (x
) &&
539 _cairo_fixed_is_integer (y
);
541 if (path
->fill_is_empty
) {
542 path
->fill_is_empty
= path
->current_point
.x
== x
&&
543 path
->current_point
.y
== y
;
547 path
->current_point
= point
;
549 _cairo_box_add_point (&path
->extents
, &point
);
551 return _cairo_path_fixed_add (path
, CAIRO_PATH_OP_LINE_TO
, &point
, 1);
555 _cairo_path_fixed_rel_line_to (cairo_path_fixed_t
*path
,
559 if (unlikely (! path
->has_current_point
))
560 return _cairo_error (CAIRO_STATUS_NO_CURRENT_POINT
);
562 return _cairo_path_fixed_line_to (path
,
563 path
->current_point
.x
+ dx
,
564 path
->current_point
.y
+ dy
);
568 _cairo_path_fixed_curve_to (cairo_path_fixed_t
*path
,
569 cairo_fixed_t x0
, cairo_fixed_t y0
,
570 cairo_fixed_t x1
, cairo_fixed_t y1
,
571 cairo_fixed_t x2
, cairo_fixed_t y2
)
573 cairo_status_t status
;
574 cairo_point_t point
[3];
576 /* If this curves does not move, replace it with a line-to.
577 * This frequently happens with rounded-rectangles and r==0.
579 if (path
->current_point
.x
== x2
&& path
->current_point
.y
== y2
) {
580 if (x1
== x2
&& x0
== x2
&& y1
== y2
&& y0
== y2
)
581 return _cairo_path_fixed_line_to (path
, x2
, y2
);
583 /* We may want to check for the absence of a cusp, in which case
584 * we can also replace the curve-to with a line-to.
588 /* make sure subpaths are started properly */
589 if (! path
->has_current_point
) {
590 status
= _cairo_path_fixed_move_to (path
, x0
, y0
);
591 assert (status
== CAIRO_STATUS_SUCCESS
);
594 status
= _cairo_path_fixed_move_to_apply (path
);
595 if (unlikely (status
))
598 /* If the previous op was a degenerate LINE_TO, drop it. */
599 if (_cairo_path_fixed_last_op (path
) == CAIRO_PATH_OP_LINE_TO
) {
600 const cairo_point_t
*p
;
602 p
= _cairo_path_fixed_penultimate_point (path
);
603 if (p
->x
== path
->current_point
.x
&& p
->y
== path
->current_point
.y
) {
604 /* previous line element was degenerate, replace */
605 _cairo_path_fixed_drop_line_to (path
);
609 point
[0].x
= x0
; point
[0].y
= y0
;
610 point
[1].x
= x1
; point
[1].y
= y1
;
611 point
[2].x
= x2
; point
[2].y
= y2
;
613 _cairo_box_add_curve_to (&path
->extents
, &path
->current_point
,
614 &point
[0], &point
[1], &point
[2]);
616 path
->current_point
= point
[2];
617 path
->has_curve_to
= TRUE
;
618 path
->stroke_is_rectilinear
= FALSE
;
619 path
->fill_is_rectilinear
= FALSE
;
620 path
->fill_maybe_region
= FALSE
;
621 path
->fill_is_empty
= FALSE
;
623 return _cairo_path_fixed_add (path
, CAIRO_PATH_OP_CURVE_TO
, point
, 3);
627 _cairo_path_fixed_rel_curve_to (cairo_path_fixed_t
*path
,
628 cairo_fixed_t dx0
, cairo_fixed_t dy0
,
629 cairo_fixed_t dx1
, cairo_fixed_t dy1
,
630 cairo_fixed_t dx2
, cairo_fixed_t dy2
)
632 if (unlikely (! path
->has_current_point
))
633 return _cairo_error (CAIRO_STATUS_NO_CURRENT_POINT
);
635 return _cairo_path_fixed_curve_to (path
,
636 path
->current_point
.x
+ dx0
,
637 path
->current_point
.y
+ dy0
,
639 path
->current_point
.x
+ dx1
,
640 path
->current_point
.y
+ dy1
,
642 path
->current_point
.x
+ dx2
,
643 path
->current_point
.y
+ dy2
);
647 _cairo_path_fixed_close_path (cairo_path_fixed_t
*path
)
649 cairo_status_t status
;
651 if (! path
->has_current_point
)
652 return CAIRO_STATUS_SUCCESS
;
655 * Add a line_to, to compute flags and solve any degeneracy.
656 * It will be removed later (if it was actually added).
658 status
= _cairo_path_fixed_line_to (path
,
659 path
->last_move_point
.x
,
660 path
->last_move_point
.y
);
661 if (unlikely (status
))
665 * If the command used to close the path is a line_to, drop it.
666 * We must check that last command is actually a line_to,
667 * because the path could have been closed with a curve_to (and
668 * the previous line_to not added as it would be degenerate).
670 if (_cairo_path_fixed_last_op (path
) == CAIRO_PATH_OP_LINE_TO
)
671 _cairo_path_fixed_drop_line_to (path
);
673 path
->needs_move_to
= TRUE
; /* After close_path, add an implicit move_to */
675 return _cairo_path_fixed_add (path
, CAIRO_PATH_OP_CLOSE_PATH
, NULL
, 0);
679 _cairo_path_fixed_get_current_point (cairo_path_fixed_t
*path
,
683 if (! path
->has_current_point
)
686 *x
= path
->current_point
.x
;
687 *y
= path
->current_point
.y
;
692 static cairo_status_t
693 _cairo_path_fixed_add (cairo_path_fixed_t
*path
,
695 const cairo_point_t
*points
,
698 cairo_path_buf_t
*buf
= cairo_path_tail (path
);
700 if (buf
->num_ops
+ 1 > buf
->size_ops
||
701 buf
->num_points
+ num_points
> buf
->size_points
)
703 buf
= _cairo_path_buf_create (buf
->num_ops
* 2, buf
->num_points
* 2);
704 if (unlikely (buf
== NULL
))
705 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
707 _cairo_path_fixed_add_buf (path
, buf
);
711 const char *op_str
[] = {
721 len
+= snprintf (buf
+ len
, sizeof (buf
), "[");
722 for (i
= 0; i
< num_points
; i
++) {
724 len
+= snprintf (buf
+ len
, sizeof (buf
), " ");
725 len
+= snprintf (buf
+ len
, sizeof (buf
), "(%f, %f)",
726 _cairo_fixed_to_double (points
[i
].x
),
727 _cairo_fixed_to_double (points
[i
].y
));
729 len
+= snprintf (buf
+ len
, sizeof (buf
), "]");
731 #define STRINGIFYFLAG(x) (path->x ? #x " " : "")
733 "_cairo_path_fixed_add (%s, %s) [%s%s%s%s%s%s%s%s]\n",
734 op_str
[(int) op
], buf
,
735 STRINGIFYFLAG(has_current_point
),
736 STRINGIFYFLAG(needs_move_to
),
737 STRINGIFYFLAG(has_extents
),
738 STRINGIFYFLAG(has_curve_to
),
739 STRINGIFYFLAG(stroke_is_rectilinear
),
740 STRINGIFYFLAG(fill_is_rectilinear
),
741 STRINGIFYFLAG(fill_is_empty
),
742 STRINGIFYFLAG(fill_maybe_region
)
747 _cairo_path_buf_add_op (buf
, op
);
748 _cairo_path_buf_add_points (buf
, points
, num_points
);
750 return CAIRO_STATUS_SUCCESS
;
754 _cairo_path_fixed_add_buf (cairo_path_fixed_t
*path
,
755 cairo_path_buf_t
*buf
)
757 cairo_list_add_tail (&buf
->link
, &cairo_path_head (path
)->link
);
760 COMPILE_TIME_ASSERT (sizeof (cairo_path_op_t
) == 1);
761 static cairo_path_buf_t
*
762 _cairo_path_buf_create (int size_ops
, int size_points
)
764 cairo_path_buf_t
*buf
;
766 /* adjust size_ops to ensure that buf->points is naturally aligned */
767 size_ops
+= sizeof (double) - ((sizeof (cairo_path_buf_t
) + size_ops
) % sizeof (double));
768 buf
= _cairo_malloc_ab_plus_c (size_points
, sizeof (cairo_point_t
), size_ops
+ sizeof (cairo_path_buf_t
));
772 buf
->size_ops
= size_ops
;
773 buf
->size_points
= size_points
;
775 buf
->op
= (cairo_path_op_t
*) (buf
+ 1);
776 buf
->points
= (cairo_point_t
*) (buf
->op
+ size_ops
);
783 _cairo_path_buf_destroy (cairo_path_buf_t
*buf
)
789 _cairo_path_buf_add_op (cairo_path_buf_t
*buf
,
792 buf
->op
[buf
->num_ops
++] = op
;
796 _cairo_path_buf_add_points (cairo_path_buf_t
*buf
,
797 const cairo_point_t
*points
,
803 memcpy (buf
->points
+ buf
->num_points
,
805 sizeof (points
[0]) * num_points
);
806 buf
->num_points
+= num_points
;
810 _cairo_path_fixed_interpret (const cairo_path_fixed_t
*path
,
811 cairo_path_fixed_move_to_func_t
*move_to
,
812 cairo_path_fixed_line_to_func_t
*line_to
,
813 cairo_path_fixed_curve_to_func_t
*curve_to
,
814 cairo_path_fixed_close_path_func_t
*close_path
,
817 const cairo_path_buf_t
*buf
;
818 cairo_status_t status
;
820 cairo_path_foreach_buf_start (buf
, path
) {
821 const cairo_point_t
*points
= buf
->points
;
824 for (i
= 0; i
< buf
->num_ops
; i
++) {
825 switch (buf
->op
[i
]) {
826 case CAIRO_PATH_OP_MOVE_TO
:
827 status
= (*move_to
) (closure
, &points
[0]);
830 case CAIRO_PATH_OP_LINE_TO
:
831 status
= (*line_to
) (closure
, &points
[0]);
834 case CAIRO_PATH_OP_CURVE_TO
:
835 status
= (*curve_to
) (closure
, &points
[0], &points
[1], &points
[2]);
840 case CAIRO_PATH_OP_CLOSE_PATH
:
841 status
= (*close_path
) (closure
);
845 if (unlikely (status
))
848 } cairo_path_foreach_buf_end (buf
, path
);
850 if (path
->needs_move_to
&& path
->has_current_point
)
851 return (*move_to
) (closure
, &path
->current_point
);
853 return CAIRO_STATUS_SUCCESS
;
856 typedef struct _cairo_path_fixed_append_closure
{
857 cairo_point_t offset
;
858 cairo_path_fixed_t
*path
;
859 } cairo_path_fixed_append_closure_t
;
861 static cairo_status_t
862 _append_move_to (void *abstract_closure
,
863 const cairo_point_t
*point
)
865 cairo_path_fixed_append_closure_t
*closure
= abstract_closure
;
867 return _cairo_path_fixed_move_to (closure
->path
,
868 point
->x
+ closure
->offset
.x
,
869 point
->y
+ closure
->offset
.y
);
872 static cairo_status_t
873 _append_line_to (void *abstract_closure
,
874 const cairo_point_t
*point
)
876 cairo_path_fixed_append_closure_t
*closure
= abstract_closure
;
878 return _cairo_path_fixed_line_to (closure
->path
,
879 point
->x
+ closure
->offset
.x
,
880 point
->y
+ closure
->offset
.y
);
883 static cairo_status_t
884 _append_curve_to (void *abstract_closure
,
885 const cairo_point_t
*p0
,
886 const cairo_point_t
*p1
,
887 const cairo_point_t
*p2
)
889 cairo_path_fixed_append_closure_t
*closure
= abstract_closure
;
891 return _cairo_path_fixed_curve_to (closure
->path
,
892 p0
->x
+ closure
->offset
.x
,
893 p0
->y
+ closure
->offset
.y
,
894 p1
->x
+ closure
->offset
.x
,
895 p1
->y
+ closure
->offset
.y
,
896 p2
->x
+ closure
->offset
.x
,
897 p2
->y
+ closure
->offset
.y
);
900 static cairo_status_t
901 _append_close_path (void *abstract_closure
)
903 cairo_path_fixed_append_closure_t
*closure
= abstract_closure
;
905 return _cairo_path_fixed_close_path (closure
->path
);
909 _cairo_path_fixed_append (cairo_path_fixed_t
*path
,
910 const cairo_path_fixed_t
*other
,
914 cairo_path_fixed_append_closure_t closure
;
917 closure
.offset
.x
= tx
;
918 closure
.offset
.y
= ty
;
920 return _cairo_path_fixed_interpret (other
,
929 _cairo_path_fixed_offset_and_scale (cairo_path_fixed_t
*path
,
932 cairo_fixed_t scalex
,
933 cairo_fixed_t scaley
)
935 cairo_path_buf_t
*buf
;
938 if (scalex
== CAIRO_FIXED_ONE
&& scaley
== CAIRO_FIXED_ONE
) {
939 _cairo_path_fixed_translate (path
, offx
, offy
);
943 path
->last_move_point
.x
= _cairo_fixed_mul (scalex
, path
->last_move_point
.x
) + offx
;
944 path
->last_move_point
.y
= _cairo_fixed_mul (scaley
, path
->last_move_point
.y
) + offy
;
945 path
->current_point
.x
= _cairo_fixed_mul (scalex
, path
->current_point
.x
) + offx
;
946 path
->current_point
.y
= _cairo_fixed_mul (scaley
, path
->current_point
.y
) + offy
;
948 path
->fill_maybe_region
= TRUE
;
950 cairo_path_foreach_buf_start (buf
, path
) {
951 for (i
= 0; i
< buf
->num_points
; i
++) {
952 if (scalex
!= CAIRO_FIXED_ONE
)
953 buf
->points
[i
].x
= _cairo_fixed_mul (buf
->points
[i
].x
, scalex
);
954 buf
->points
[i
].x
+= offx
;
956 if (scaley
!= CAIRO_FIXED_ONE
)
957 buf
->points
[i
].y
= _cairo_fixed_mul (buf
->points
[i
].y
, scaley
);
958 buf
->points
[i
].y
+= offy
;
960 if (path
->fill_maybe_region
) {
961 path
->fill_maybe_region
= _cairo_fixed_is_integer (buf
->points
[i
].x
) &&
962 _cairo_fixed_is_integer (buf
->points
[i
].y
);
965 } cairo_path_foreach_buf_end (buf
, path
);
967 path
->fill_maybe_region
&= path
->fill_is_rectilinear
;
969 path
->extents
.p1
.x
= _cairo_fixed_mul (scalex
, path
->extents
.p1
.x
) + offx
;
970 path
->extents
.p2
.x
= _cairo_fixed_mul (scalex
, path
->extents
.p2
.x
) + offx
;
972 cairo_fixed_t t
= path
->extents
.p1
.x
;
973 path
->extents
.p1
.x
= path
->extents
.p2
.x
;
974 path
->extents
.p2
.x
= t
;
977 path
->extents
.p1
.y
= _cairo_fixed_mul (scaley
, path
->extents
.p1
.y
) + offy
;
978 path
->extents
.p2
.y
= _cairo_fixed_mul (scaley
, path
->extents
.p2
.y
) + offy
;
980 cairo_fixed_t t
= path
->extents
.p1
.y
;
981 path
->extents
.p1
.y
= path
->extents
.p2
.y
;
982 path
->extents
.p2
.y
= t
;
987 _cairo_path_fixed_translate (cairo_path_fixed_t
*path
,
991 cairo_path_buf_t
*buf
;
994 if (offx
== 0 && offy
== 0)
997 path
->last_move_point
.x
+= offx
;
998 path
->last_move_point
.y
+= offy
;
999 path
->current_point
.x
+= offx
;
1000 path
->current_point
.y
+= offy
;
1002 path
->fill_maybe_region
= TRUE
;
1004 cairo_path_foreach_buf_start (buf
, path
) {
1005 for (i
= 0; i
< buf
->num_points
; i
++) {
1006 buf
->points
[i
].x
+= offx
;
1007 buf
->points
[i
].y
+= offy
;
1009 if (path
->fill_maybe_region
) {
1010 path
->fill_maybe_region
= _cairo_fixed_is_integer (buf
->points
[i
].x
) &&
1011 _cairo_fixed_is_integer (buf
->points
[i
].y
);
1014 } cairo_path_foreach_buf_end (buf
, path
);
1016 path
->fill_maybe_region
&= path
->fill_is_rectilinear
;
1018 path
->extents
.p1
.x
+= offx
;
1019 path
->extents
.p1
.y
+= offy
;
1020 path
->extents
.p2
.x
+= offx
;
1021 path
->extents
.p2
.y
+= offy
;
1026 _cairo_path_fixed_transform_point (cairo_point_t
*p
,
1027 const cairo_matrix_t
*matrix
)
1031 dx
= _cairo_fixed_to_double (p
->x
);
1032 dy
= _cairo_fixed_to_double (p
->y
);
1033 cairo_matrix_transform_point (matrix
, &dx
, &dy
);
1034 p
->x
= _cairo_fixed_from_double (dx
);
1035 p
->y
= _cairo_fixed_from_double (dy
);
1039 * _cairo_path_fixed_transform:
1040 * @path: a #cairo_path_fixed_t to be transformed
1041 * @matrix: a #cairo_matrix_t
1043 * Transform the fixed-point path according to the given matrix.
1044 * There is a fast path for the case where @matrix has no rotation
1048 _cairo_path_fixed_transform (cairo_path_fixed_t
*path
,
1049 const cairo_matrix_t
*matrix
)
1051 cairo_box_t extents
;
1052 cairo_point_t point
;
1053 cairo_path_buf_t
*buf
;
1056 if (matrix
->yx
== 0.0 && matrix
->xy
== 0.0) {
1057 /* Fast path for the common case of scale+transform */
1058 _cairo_path_fixed_offset_and_scale (path
,
1059 _cairo_fixed_from_double (matrix
->x0
),
1060 _cairo_fixed_from_double (matrix
->y0
),
1061 _cairo_fixed_from_double (matrix
->xx
),
1062 _cairo_fixed_from_double (matrix
->yy
));
1066 _cairo_path_fixed_transform_point (&path
->last_move_point
, matrix
);
1067 _cairo_path_fixed_transform_point (&path
->current_point
, matrix
);
1069 buf
= cairo_path_head (path
);
1070 if (buf
->num_points
== 0)
1073 extents
= path
->extents
;
1074 point
= buf
->points
[0];
1075 _cairo_path_fixed_transform_point (&point
, matrix
);
1076 _cairo_box_set (&path
->extents
, &point
, &point
);
1078 cairo_path_foreach_buf_start (buf
, path
) {
1079 for (i
= 0; i
< buf
->num_points
; i
++) {
1080 _cairo_path_fixed_transform_point (&buf
->points
[i
], matrix
);
1081 _cairo_box_add_point (&path
->extents
, &buf
->points
[i
]);
1083 } cairo_path_foreach_buf_end (buf
, path
);
1085 if (path
->has_curve_to
) {
1086 cairo_bool_t is_tight
;
1088 _cairo_matrix_transform_bounding_box_fixed (matrix
, &extents
, &is_tight
);
1090 cairo_bool_t has_extents
;
1092 has_extents
= _cairo_path_bounder_extents (path
, &extents
);
1093 assert (has_extents
);
1095 path
->extents
= extents
;
1098 /* flags might become more strict than needed */
1099 path
->stroke_is_rectilinear
= FALSE
;
1100 path
->fill_is_rectilinear
= FALSE
;
1101 path
->fill_is_empty
= FALSE
;
1102 path
->fill_maybe_region
= FALSE
;
1105 /* Closure for path flattening */
1106 typedef struct cairo_path_flattener
{
1108 cairo_point_t current_point
;
1109 cairo_path_fixed_move_to_func_t
*move_to
;
1110 cairo_path_fixed_line_to_func_t
*line_to
;
1111 cairo_path_fixed_close_path_func_t
*close_path
;
1115 static cairo_status_t
1116 _cpf_move_to (void *closure
,
1117 const cairo_point_t
*point
)
1119 cpf_t
*cpf
= closure
;
1121 cpf
->current_point
= *point
;
1123 return cpf
->move_to (cpf
->closure
, point
);
1126 static cairo_status_t
1127 _cpf_line_to (void *closure
,
1128 const cairo_point_t
*point
)
1130 cpf_t
*cpf
= closure
;
1132 cpf
->current_point
= *point
;
1134 return cpf
->line_to (cpf
->closure
, point
);
1137 static cairo_status_t
1138 _cpf_curve_to (void *closure
,
1139 const cairo_point_t
*p1
,
1140 const cairo_point_t
*p2
,
1141 const cairo_point_t
*p3
)
1143 cpf_t
*cpf
= closure
;
1144 cairo_spline_t spline
;
1146 cairo_point_t
*p0
= &cpf
->current_point
;
1148 if (! _cairo_spline_init (&spline
,
1149 (cairo_spline_add_point_func_t
)cpf
->line_to
,
1153 return _cpf_line_to (closure
, p3
);
1156 cpf
->current_point
= *p3
;
1158 return _cairo_spline_decompose (&spline
, cpf
->tolerance
);
1161 static cairo_status_t
1162 _cpf_close_path (void *closure
)
1164 cpf_t
*cpf
= closure
;
1166 return cpf
->close_path (cpf
->closure
);
1170 _cairo_path_fixed_interpret_flat (const cairo_path_fixed_t
*path
,
1171 cairo_path_fixed_move_to_func_t
*move_to
,
1172 cairo_path_fixed_line_to_func_t
*line_to
,
1173 cairo_path_fixed_close_path_func_t
*close_path
,
1179 if (! path
->has_curve_to
) {
1180 return _cairo_path_fixed_interpret (path
,
1188 flattener
.tolerance
= tolerance
;
1189 flattener
.move_to
= move_to
;
1190 flattener
.line_to
= line_to
;
1191 flattener
.close_path
= close_path
;
1192 flattener
.closure
= closure
;
1193 return _cairo_path_fixed_interpret (path
,
1202 _canonical_box (cairo_box_t
*box
,
1203 const cairo_point_t
*p1
,
1204 const cairo_point_t
*p2
)
1206 if (p1
->x
<= p2
->x
) {
1214 if (p1
->y
<= p2
->y
) {
1223 static inline cairo_bool_t
1224 _path_is_quad (const cairo_path_fixed_t
*path
)
1226 const cairo_path_buf_t
*buf
= cairo_path_head (path
);
1228 /* Do we have the right number of ops? */
1229 if (buf
->num_ops
< 4 || buf
->num_ops
> 6)
1232 /* Check whether the ops are those that would be used for a rectangle */
1233 if (buf
->op
[0] != CAIRO_PATH_OP_MOVE_TO
||
1234 buf
->op
[1] != CAIRO_PATH_OP_LINE_TO
||
1235 buf
->op
[2] != CAIRO_PATH_OP_LINE_TO
||
1236 buf
->op
[3] != CAIRO_PATH_OP_LINE_TO
)
1241 /* we accept an implicit close for filled paths */
1242 if (buf
->num_ops
> 4) {
1243 /* Now, there are choices. The rectangle might end with a LINE_TO
1244 * (to the original point), but this isn't required. If it
1245 * doesn't, then it must end with a CLOSE_PATH. */
1246 if (buf
->op
[4] == CAIRO_PATH_OP_LINE_TO
) {
1247 if (buf
->points
[4].x
!= buf
->points
[0].x
||
1248 buf
->points
[4].y
!= buf
->points
[0].y
)
1250 } else if (buf
->op
[4] != CAIRO_PATH_OP_CLOSE_PATH
) {
1254 if (buf
->num_ops
== 6) {
1255 /* A trailing CLOSE_PATH or MOVE_TO is ok */
1256 if (buf
->op
[5] != CAIRO_PATH_OP_MOVE_TO
&&
1257 buf
->op
[5] != CAIRO_PATH_OP_CLOSE_PATH
)
1265 static inline cairo_bool_t
1266 _points_form_rect (const cairo_point_t
*points
)
1268 if (points
[0].y
== points
[1].y
&&
1269 points
[1].x
== points
[2].x
&&
1270 points
[2].y
== points
[3].y
&&
1271 points
[3].x
== points
[0].x
)
1273 if (points
[0].x
== points
[1].x
&&
1274 points
[1].y
== points
[2].y
&&
1275 points
[2].x
== points
[3].x
&&
1276 points
[3].y
== points
[0].y
)
1282 * Check whether the given path contains a single rectangle.
1285 _cairo_path_fixed_is_box (const cairo_path_fixed_t
*path
,
1288 const cairo_path_buf_t
*buf
;
1290 if (! path
->fill_is_rectilinear
)
1293 if (! _path_is_quad (path
))
1296 buf
= cairo_path_head (path
);
1297 if (_points_form_rect (buf
->points
)) {
1298 _canonical_box (box
, &buf
->points
[0], &buf
->points
[2]);
1305 /* Determine whether two lines A->B and C->D intersect based on the
1306 * algorithm described here: http://paulbourke.net/geometry/pointlineplane/ */
1307 static inline cairo_bool_t
1308 _lines_intersect_or_are_coincident (cairo_point_t a
,
1313 cairo_int64_t numerator_a
, numerator_b
, denominator
;
1314 cairo_bool_t denominator_negative
;
1316 denominator
= _cairo_int64_sub (_cairo_int32x32_64_mul (d
.y
- c
.y
, b
.x
- a
.x
),
1317 _cairo_int32x32_64_mul (d
.x
- c
.x
, b
.y
- a
.y
));
1318 numerator_a
= _cairo_int64_sub (_cairo_int32x32_64_mul (d
.x
- c
.x
, a
.y
- c
.y
),
1319 _cairo_int32x32_64_mul (d
.y
- c
.y
, a
.x
- c
.x
));
1320 numerator_b
= _cairo_int64_sub (_cairo_int32x32_64_mul (b
.x
- a
.x
, a
.y
- c
.y
),
1321 _cairo_int32x32_64_mul (b
.y
- a
.y
, a
.x
- c
.x
));
1323 if (_cairo_int64_is_zero (denominator
)) {
1324 /* If the denominator and numerators are both zero,
1325 * the lines are coincident. */
1326 if (_cairo_int64_is_zero (numerator_a
) && _cairo_int64_is_zero (numerator_b
))
1329 /* Otherwise, a zero denominator indicates the lines are
1330 * parallel and never intersect. */
1334 /* The lines intersect if both quotients are between 0 and 1 (exclusive). */
1336 /* We first test whether either quotient is a negative number. */
1337 denominator_negative
= _cairo_int64_negative (denominator
);
1338 if (_cairo_int64_negative (numerator_a
) ^ denominator_negative
)
1340 if (_cairo_int64_negative (numerator_b
) ^ denominator_negative
)
1343 /* A zero quotient indicates an "intersection" at an endpoint, which
1344 * we aren't considering a true intersection. */
1345 if (_cairo_int64_is_zero (numerator_a
) || _cairo_int64_is_zero (numerator_b
))
1348 /* If the absolute value of the numerator is larger than or equal to the
1349 * denominator the result of the division would be greater than or equal
1351 if (! denominator_negative
) {
1352 if (! _cairo_int64_lt (numerator_a
, denominator
) ||
1353 ! _cairo_int64_lt (numerator_b
, denominator
))
1356 if (! _cairo_int64_lt (denominator
, numerator_a
) ||
1357 ! _cairo_int64_lt (denominator
, numerator_b
))
1365 _cairo_path_fixed_is_simple_quad (const cairo_path_fixed_t
*path
)
1367 const cairo_point_t
*points
;
1369 if (! _path_is_quad (path
))
1372 points
= cairo_path_head (path
)->points
;
1373 if (_points_form_rect (points
))
1376 if (_lines_intersect_or_are_coincident (points
[0], points
[1],
1377 points
[3], points
[2]))
1380 if (_lines_intersect_or_are_coincident (points
[0], points
[3],
1381 points
[1], points
[2]))
1388 _cairo_path_fixed_is_stroke_box (const cairo_path_fixed_t
*path
,
1391 const cairo_path_buf_t
*buf
= cairo_path_head (path
);
1393 if (! path
->fill_is_rectilinear
)
1396 /* Do we have the right number of ops? */
1397 if (buf
->num_ops
!= 5)
1400 /* Check whether the ops are those that would be used for a rectangle */
1401 if (buf
->op
[0] != CAIRO_PATH_OP_MOVE_TO
||
1402 buf
->op
[1] != CAIRO_PATH_OP_LINE_TO
||
1403 buf
->op
[2] != CAIRO_PATH_OP_LINE_TO
||
1404 buf
->op
[3] != CAIRO_PATH_OP_LINE_TO
||
1405 buf
->op
[4] != CAIRO_PATH_OP_CLOSE_PATH
)
1410 /* Ok, we may have a box, if the points line up */
1411 if (buf
->points
[0].y
== buf
->points
[1].y
&&
1412 buf
->points
[1].x
== buf
->points
[2].x
&&
1413 buf
->points
[2].y
== buf
->points
[3].y
&&
1414 buf
->points
[3].x
== buf
->points
[0].x
)
1416 _canonical_box (box
, &buf
->points
[0], &buf
->points
[2]);
1420 if (buf
->points
[0].x
== buf
->points
[1].x
&&
1421 buf
->points
[1].y
== buf
->points
[2].y
&&
1422 buf
->points
[2].x
== buf
->points
[3].x
&&
1423 buf
->points
[3].y
== buf
->points
[0].y
)
1425 _canonical_box (box
, &buf
->points
[0], &buf
->points
[2]);
1433 * Check whether the given path contains a single rectangle
1434 * that is logically equivalent to:
1435 * <informalexample><programlisting>
1436 * cairo_move_to (cr, x, y);
1437 * cairo_rel_line_to (cr, width, 0);
1438 * cairo_rel_line_to (cr, 0, height);
1439 * cairo_rel_line_to (cr, -width, 0);
1440 * cairo_close_path (cr);
1441 * </programlisting></informalexample>
1444 _cairo_path_fixed_is_rectangle (const cairo_path_fixed_t
*path
,
1447 const cairo_path_buf_t
*buf
;
1449 if (! _cairo_path_fixed_is_box (path
, box
))
1452 /* This check is valid because the current implementation of
1453 * _cairo_path_fixed_is_box () only accepts rectangles like:
1454 * move,line,line,line[,line|close[,close|move]]. */
1455 buf
= cairo_path_head (path
);
1456 if (buf
->num_ops
> 4)
1463 _cairo_path_fixed_iter_init (cairo_path_fixed_iter_t
*iter
,
1464 const cairo_path_fixed_t
*path
)
1466 iter
->first
= iter
->buf
= cairo_path_head (path
);
1472 _cairo_path_fixed_iter_next_op (cairo_path_fixed_iter_t
*iter
)
1474 if (++iter
->n_op
>= iter
->buf
->num_ops
) {
1475 iter
->buf
= cairo_path_buf_next (iter
->buf
);
1476 if (iter
->buf
== iter
->first
) {
1489 _cairo_path_fixed_iter_is_fill_box (cairo_path_fixed_iter_t
*_iter
,
1492 cairo_point_t points
[5];
1493 cairo_path_fixed_iter_t iter
;
1495 if (_iter
->buf
== NULL
)
1500 if (iter
.n_op
== iter
.buf
->num_ops
&& ! _cairo_path_fixed_iter_next_op (&iter
))
1503 /* Check whether the ops are those that would be used for a rectangle */
1504 if (iter
.buf
->op
[iter
.n_op
] != CAIRO_PATH_OP_MOVE_TO
)
1506 points
[0] = iter
.buf
->points
[iter
.n_point
++];
1507 if (! _cairo_path_fixed_iter_next_op (&iter
))
1510 if (iter
.buf
->op
[iter
.n_op
] != CAIRO_PATH_OP_LINE_TO
)
1512 points
[1] = iter
.buf
->points
[iter
.n_point
++];
1513 if (! _cairo_path_fixed_iter_next_op (&iter
))
1516 /* a horizontal/vertical closed line is also a degenerate rectangle */
1517 switch (iter
.buf
->op
[iter
.n_op
]) {
1518 case CAIRO_PATH_OP_CLOSE_PATH
:
1519 _cairo_path_fixed_iter_next_op (&iter
);
1520 case CAIRO_PATH_OP_MOVE_TO
: /* implicit close */
1521 box
->p1
= box
->p2
= points
[0];
1526 case CAIRO_PATH_OP_LINE_TO
:
1530 points
[2] = iter
.buf
->points
[iter
.n_point
++];
1531 if (! _cairo_path_fixed_iter_next_op (&iter
))
1534 if (iter
.buf
->op
[iter
.n_op
] != CAIRO_PATH_OP_LINE_TO
)
1536 points
[3] = iter
.buf
->points
[iter
.n_point
++];
1538 /* Now, there are choices. The rectangle might end with a LINE_TO
1539 * (to the original point), but this isn't required. If it
1540 * doesn't, then it must end with a CLOSE_PATH (which may be implicit). */
1541 if (! _cairo_path_fixed_iter_next_op (&iter
)) {
1542 /* implicit close due to fill */
1543 } else if (iter
.buf
->op
[iter
.n_op
] == CAIRO_PATH_OP_LINE_TO
) {
1544 points
[4] = iter
.buf
->points
[iter
.n_point
++];
1545 if (points
[4].x
!= points
[0].x
|| points
[4].y
!= points
[0].y
)
1547 _cairo_path_fixed_iter_next_op (&iter
);
1548 } else if (iter
.buf
->op
[iter
.n_op
] == CAIRO_PATH_OP_CLOSE_PATH
) {
1549 _cairo_path_fixed_iter_next_op (&iter
);
1550 } else if (iter
.buf
->op
[iter
.n_op
] == CAIRO_PATH_OP_MOVE_TO
) {
1551 /* implicit close-path due to new-sub-path */
1556 /* Ok, we may have a box, if the points line up */
1557 if (points
[0].y
== points
[1].y
&&
1558 points
[1].x
== points
[2].x
&&
1559 points
[2].y
== points
[3].y
&&
1560 points
[3].x
== points
[0].x
)
1562 box
->p1
= points
[0];
1563 box
->p2
= points
[2];
1568 if (points
[0].x
== points
[1].x
&&
1569 points
[1].y
== points
[2].y
&&
1570 points
[2].x
== points
[3].x
&&
1571 points
[3].y
== points
[0].y
)
1573 box
->p1
= points
[1];
1574 box
->p2
= points
[3];
1583 _cairo_path_fixed_iter_at_end (const cairo_path_fixed_iter_t
*iter
)
1585 if (iter
->buf
== NULL
)
1588 return iter
->n_op
== iter
->buf
->num_ops
;