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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 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-path-fixed-private.h"
43 /* private functions */
45 _cairo_path_fixed_add (cairo_path_fixed_t
*path
,
47 cairo_point_t
*points
,
51 _cairo_path_fixed_add_buf (cairo_path_fixed_t
*path
,
52 cairo_path_buf_t
*buf
);
54 static cairo_path_buf_t
*
55 _cairo_path_buf_create (int buf_size
);
58 _cairo_path_buf_destroy (cairo_path_buf_t
*buf
);
61 _cairo_path_buf_add_op (cairo_path_buf_t
*buf
,
65 _cairo_path_buf_add_points (cairo_path_buf_t
*buf
,
66 cairo_point_t
*points
,
70 _cairo_path_fixed_init (cairo_path_fixed_t
*path
)
72 path
->buf_head
.base
.next
= NULL
;
73 path
->buf_head
.base
.prev
= NULL
;
74 path
->buf_tail
= &path
->buf_head
.base
;
76 path
->buf_head
.base
.num_ops
= 0;
77 path
->buf_head
.base
.num_points
= 0;
78 path
->buf_head
.base
.buf_size
= CAIRO_PATH_BUF_SIZE
;
79 path
->buf_head
.base
.op
= path
->buf_head
.op
;
80 path
->buf_head
.base
.points
= path
->buf_head
.points
;
82 path
->current_point
.x
= 0;
83 path
->current_point
.y
= 0;
84 path
->has_current_point
= FALSE
;
85 path
->has_curve_to
= FALSE
;
86 path
->last_move_point
= path
->current_point
;
90 _cairo_path_fixed_init_copy (cairo_path_fixed_t
*path
,
91 cairo_path_fixed_t
*other
)
93 cairo_path_buf_t
*buf
, *other_buf
;
94 unsigned int num_points
, num_ops
, buf_size
;
96 _cairo_path_fixed_init (path
);
98 path
->current_point
= other
->current_point
;
99 path
->has_current_point
= other
->has_current_point
;
100 path
->has_curve_to
= other
->has_curve_to
;
101 path
->last_move_point
= other
->last_move_point
;
103 path
->buf_head
.base
.num_ops
= other
->buf_head
.base
.num_ops
;
104 path
->buf_head
.base
.num_points
= other
->buf_head
.base
.num_points
;
105 path
->buf_head
.base
.buf_size
= other
->buf_head
.base
.buf_size
;
106 memcpy (path
->buf_head
.op
, other
->buf_head
.base
.op
,
107 other
->buf_head
.base
.num_ops
* sizeof (other
->buf_head
.op
[0]));
108 memcpy (path
->buf_head
.points
, other
->buf_head
.points
,
109 other
->buf_head
.base
.num_points
* sizeof (other
->buf_head
.points
[0]));
111 num_points
= num_ops
= 0;
112 for (other_buf
= other
->buf_head
.base
.next
;
114 other_buf
= other_buf
->next
)
116 num_ops
+= other_buf
->num_ops
;
117 num_points
+= other_buf
->num_points
;
120 buf_size
= MAX (num_ops
, (num_points
+ 1) / 2);
122 buf
= _cairo_path_buf_create (buf_size
);
124 _cairo_path_fixed_fini (path
);
125 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
128 for (other_buf
= other
->buf_head
.base
.next
;
130 other_buf
= other_buf
->next
)
132 memcpy (buf
->op
+ buf
->num_ops
, other_buf
->op
,
133 other_buf
->num_ops
* sizeof (buf
->op
[0]));
134 buf
->num_ops
+= other_buf
->num_ops
;
136 memcpy (buf
->points
+ buf
->num_points
, other_buf
->points
,
137 other_buf
->num_points
* sizeof (buf
->points
[0]));
138 buf
->num_points
+= other_buf
->num_points
;
141 _cairo_path_fixed_add_buf (path
, buf
);
144 return CAIRO_STATUS_SUCCESS
;
148 _cairo_path_fixed_create (void)
150 cairo_path_fixed_t
*path
;
152 path
= malloc (sizeof (cairo_path_fixed_t
));
154 _cairo_error_throw (CAIRO_STATUS_NO_MEMORY
);
158 _cairo_path_fixed_init (path
);
163 _cairo_path_fixed_fini (cairo_path_fixed_t
*path
)
165 cairo_path_buf_t
*buf
;
167 buf
= path
->buf_head
.base
.next
;
169 cairo_path_buf_t
*this = buf
;
171 _cairo_path_buf_destroy (this);
173 path
->buf_head
.base
.next
= NULL
;
174 path
->buf_head
.base
.prev
= NULL
;
175 path
->buf_tail
= &path
->buf_head
.base
;
176 path
->buf_head
.base
.num_ops
= 0;
177 path
->buf_head
.base
.num_points
= 0;
179 path
->has_current_point
= FALSE
;
180 path
->has_curve_to
= FALSE
;
184 _cairo_path_fixed_destroy (cairo_path_fixed_t
*path
)
186 _cairo_path_fixed_fini (path
);
191 _cairo_path_fixed_move_to (cairo_path_fixed_t
*path
,
195 cairo_status_t status
;
201 /* If the previous op was also a MOVE_TO, then just change its
202 * point rather than adding a new op. */
203 if (path
->buf_tail
&& path
->buf_tail
->num_ops
&&
204 path
->buf_tail
->op
[path
->buf_tail
->num_ops
- 1] == CAIRO_PATH_OP_MOVE_TO
)
206 cairo_point_t
*last_move_to_point
;
207 last_move_to_point
= &path
->buf_tail
->points
[path
->buf_tail
->num_points
- 1];
208 *last_move_to_point
= point
;
210 status
= _cairo_path_fixed_add (path
, CAIRO_PATH_OP_MOVE_TO
, &point
, 1);
215 path
->current_point
= point
;
216 path
->has_current_point
= TRUE
;
217 path
->last_move_point
= path
->current_point
;
219 return CAIRO_STATUS_SUCCESS
;
223 _cairo_path_fixed_new_sub_path (cairo_path_fixed_t
*path
)
225 path
->has_current_point
= FALSE
;
229 _cairo_path_fixed_rel_move_to (cairo_path_fixed_t
*path
,
235 if (! path
->has_current_point
)
236 return _cairo_error (CAIRO_STATUS_NO_CURRENT_POINT
);
238 x
= path
->current_point
.x
+ dx
;
239 y
= path
->current_point
.y
+ dy
;
241 return _cairo_path_fixed_move_to (path
, x
, y
);
245 _cairo_path_fixed_line_to (cairo_path_fixed_t
*path
,
249 cairo_status_t status
;
255 /* When there is not yet a current point, the line_to operation
256 * becomes a move_to instead. Note: We have to do this by
257 * explicitly calling into _cairo_path_fixed_line_to to ensure
258 * that the last_move_point state is updated properly.
260 if (! path
->has_current_point
)
261 status
= _cairo_path_fixed_move_to (path
, point
.x
, point
.y
);
263 status
= _cairo_path_fixed_add (path
, CAIRO_PATH_OP_LINE_TO
, &point
, 1);
268 path
->current_point
= point
;
269 path
->has_current_point
= TRUE
;
271 return CAIRO_STATUS_SUCCESS
;
275 _cairo_path_fixed_rel_line_to (cairo_path_fixed_t
*path
,
281 if (! path
->has_current_point
)
282 return _cairo_error (CAIRO_STATUS_NO_CURRENT_POINT
);
284 x
= path
->current_point
.x
+ dx
;
285 y
= path
->current_point
.y
+ dy
;
287 return _cairo_path_fixed_line_to (path
, x
, y
);
291 _cairo_path_fixed_curve_to (cairo_path_fixed_t
*path
,
292 cairo_fixed_t x0
, cairo_fixed_t y0
,
293 cairo_fixed_t x1
, cairo_fixed_t y1
,
294 cairo_fixed_t x2
, cairo_fixed_t y2
)
296 cairo_status_t status
;
297 cairo_point_t point
[3];
299 point
[0].x
= x0
; point
[0].y
= y0
;
300 point
[1].x
= x1
; point
[1].y
= y1
;
301 point
[2].x
= x2
; point
[2].y
= y2
;
303 if (! path
->has_current_point
) {
304 status
= _cairo_path_fixed_add (path
, CAIRO_PATH_OP_MOVE_TO
,
310 status
= _cairo_path_fixed_add (path
, CAIRO_PATH_OP_CURVE_TO
, point
, 3);
314 path
->current_point
= point
[2];
315 path
->has_current_point
= TRUE
;
316 path
->has_curve_to
= TRUE
;
318 return CAIRO_STATUS_SUCCESS
;
322 _cairo_path_fixed_rel_curve_to (cairo_path_fixed_t
*path
,
323 cairo_fixed_t dx0
, cairo_fixed_t dy0
,
324 cairo_fixed_t dx1
, cairo_fixed_t dy1
,
325 cairo_fixed_t dx2
, cairo_fixed_t dy2
)
327 cairo_fixed_t x0
, y0
;
328 cairo_fixed_t x1
, y1
;
329 cairo_fixed_t x2
, y2
;
331 if (! path
->has_current_point
)
332 return _cairo_error (CAIRO_STATUS_NO_CURRENT_POINT
);
334 x0
= path
->current_point
.x
+ dx0
;
335 y0
= path
->current_point
.y
+ dy0
;
337 x1
= path
->current_point
.x
+ dx1
;
338 y1
= path
->current_point
.y
+ dy1
;
340 x2
= path
->current_point
.x
+ dx2
;
341 y2
= path
->current_point
.y
+ dy2
;
343 return _cairo_path_fixed_curve_to (path
,
350 _cairo_path_fixed_close_path (cairo_path_fixed_t
*path
)
352 cairo_status_t status
;
354 if (! path
->has_current_point
)
355 return CAIRO_STATUS_SUCCESS
;
357 status
= _cairo_path_fixed_add (path
, CAIRO_PATH_OP_CLOSE_PATH
, NULL
, 0);
361 status
= _cairo_path_fixed_move_to (path
,
362 path
->last_move_point
.x
,
363 path
->last_move_point
.y
);
367 return CAIRO_STATUS_SUCCESS
;
371 _cairo_path_fixed_get_current_point (cairo_path_fixed_t
*path
,
375 if (! path
->has_current_point
)
378 *x
= path
->current_point
.x
;
379 *y
= path
->current_point
.y
;
384 static cairo_status_t
385 _cairo_path_fixed_add (cairo_path_fixed_t
*path
,
387 cairo_point_t
*points
,
390 cairo_path_buf_t
*buf
= path
->buf_tail
;
392 if (buf
->num_ops
+ 1 > buf
->buf_size
||
393 buf
->num_points
+ num_points
> 2 * buf
->buf_size
)
395 buf
= _cairo_path_buf_create (buf
->buf_size
* 2);
397 return _cairo_error (CAIRO_STATUS_NO_MEMORY
);
399 _cairo_path_fixed_add_buf (path
, buf
);
402 _cairo_path_buf_add_op (buf
, op
);
403 _cairo_path_buf_add_points (buf
, points
, num_points
);
405 return CAIRO_STATUS_SUCCESS
;
409 _cairo_path_fixed_add_buf (cairo_path_fixed_t
*path
,
410 cairo_path_buf_t
*buf
)
413 buf
->prev
= path
->buf_tail
;
415 path
->buf_tail
->next
= buf
;
416 path
->buf_tail
= buf
;
419 static cairo_path_buf_t
*
420 _cairo_path_buf_create (int buf_size
)
422 cairo_path_buf_t
*buf
;
424 /* adjust buf_size to ensure that buf->points is naturally aligned */
425 buf_size
+= sizeof (double)
426 - ((buf_size
+ sizeof (cairo_path_buf_t
)) & (sizeof (double)-1));
427 buf
= _cairo_malloc_ab_plus_c (buf_size
,
428 sizeof (cairo_path_op_t
) +
429 2 * sizeof (cairo_point_t
),
430 sizeof (cairo_path_buf_t
));
436 buf
->buf_size
= buf_size
;
438 buf
->op
= (cairo_path_op_t
*) (buf
+ 1);
439 buf
->points
= (cairo_point_t
*) (buf
->op
+ buf_size
);
446 _cairo_path_buf_destroy (cairo_path_buf_t
*buf
)
452 _cairo_path_buf_add_op (cairo_path_buf_t
*buf
,
455 buf
->op
[buf
->num_ops
++] = op
;
459 _cairo_path_buf_add_points (cairo_path_buf_t
*buf
,
460 cairo_point_t
*points
,
465 for (i
=0; i
< num_points
; i
++) {
466 buf
->points
[buf
->num_points
++] = points
[i
];
470 static int const num_args
[] =
472 1, /* cairo_path_move_to */
473 1, /* cairo_path_op_line_to */
474 3, /* cairo_path_op_curve_to */
475 0, /* cairo_path_op_close_path */
479 _cairo_path_fixed_interpret (const cairo_path_fixed_t
*path
,
480 cairo_direction_t dir
,
481 cairo_path_fixed_move_to_func_t
*move_to
,
482 cairo_path_fixed_line_to_func_t
*line_to
,
483 cairo_path_fixed_curve_to_func_t
*curve_to
,
484 cairo_path_fixed_close_path_func_t
*close_path
,
487 cairo_status_t status
;
488 const cairo_path_buf_t
*buf
;
490 cairo_bool_t forward
= (dir
== CAIRO_DIRECTION_FORWARD
);
491 int step
= forward
? 1 : -1;
493 for (buf
= forward
? &path
->buf_head
.base
: path
->buf_tail
;
495 buf
= forward
? buf
->next
: buf
->prev
)
497 cairo_point_t
*points
;
502 points
= buf
->points
;
504 start
= buf
->num_ops
- 1;
506 points
= buf
->points
+ buf
->num_points
;
509 for (i
=start
; i
!= stop
; i
+= step
) {
513 points
-= num_args
[(int) op
];
517 case CAIRO_PATH_OP_MOVE_TO
:
518 status
= (*move_to
) (closure
, &points
[0]);
520 case CAIRO_PATH_OP_LINE_TO
:
521 status
= (*line_to
) (closure
, &points
[0]);
523 case CAIRO_PATH_OP_CURVE_TO
:
524 status
= (*curve_to
) (closure
, &points
[0], &points
[1], &points
[2]);
526 case CAIRO_PATH_OP_CLOSE_PATH
:
528 status
= (*close_path
) (closure
);
535 points
+= num_args
[(int) op
];
541 return CAIRO_STATUS_SUCCESS
;
544 static cairo_status_t
545 _append_move_to (void *closure
,
546 cairo_point_t
*point
)
548 cairo_path_fixed_t
*path
= (cairo_path_fixed_t
*) closure
;
549 return _cairo_path_fixed_move_to (path
, point
->x
, point
->y
);
552 static cairo_status_t
553 _append_line_to (void *closure
,
554 cairo_point_t
*point
)
556 cairo_path_fixed_t
*path
= (cairo_path_fixed_t
*) closure
;
557 return _cairo_path_fixed_line_to (path
, point
->x
, point
->y
);
560 static cairo_status_t
561 _append_curve_to (void *closure
,
566 cairo_path_fixed_t
*path
= (cairo_path_fixed_t
*) closure
;
567 return _cairo_path_fixed_curve_to (path
, p0
->x
, p0
->y
, p1
->x
, p1
->y
, p2
->x
, p2
->y
);
570 static cairo_status_t
571 _append_close_path (void *closure
)
573 cairo_path_fixed_t
*path
= (cairo_path_fixed_t
*) closure
;
574 return _cairo_path_fixed_close_path (path
);
577 cairo_private cairo_status_t
578 _cairo_path_fixed_append (cairo_path_fixed_t
*path
,
579 const cairo_path_fixed_t
*other
,
580 cairo_direction_t dir
)
582 return _cairo_path_fixed_interpret (other
, dir
,
591 _cairo_path_fixed_offset_and_scale (cairo_path_fixed_t
*path
,
594 cairo_fixed_t scalex
,
595 cairo_fixed_t scaley
)
597 cairo_path_buf_t
*buf
= &path
->buf_head
.base
;
601 for (i
= 0; i
< buf
->num_points
; i
++) {
602 if (scalex
!= CAIRO_FIXED_ONE
)
603 buf
->points
[i
].x
= _cairo_fixed_mul (buf
->points
[i
].x
, scalex
);
604 buf
->points
[i
].x
+= offx
;
606 if (scaley
!= CAIRO_FIXED_ONE
)
607 buf
->points
[i
].y
= _cairo_fixed_mul (buf
->points
[i
].y
, scaley
);
608 buf
->points
[i
].y
+= offy
;
616 * _cairo_path_fixed_transform:
617 * @path: a #cairo_path_fixed_t to be transformed
618 * @matrix: a #cairo_matrix_t
620 * Transform the fixed-point path according to the given matrix.
621 * There is a fast path for the case where @matrix has no rotation
625 _cairo_path_fixed_transform (cairo_path_fixed_t
*path
,
626 cairo_matrix_t
*matrix
)
628 cairo_path_buf_t
*buf
;
632 if (matrix
->yx
== 0.0 && matrix
->xy
== 0.0) {
633 /* Fast path for the common case of scale+transform */
634 _cairo_path_fixed_offset_and_scale (path
,
635 _cairo_fixed_from_double (matrix
->x0
),
636 _cairo_fixed_from_double (matrix
->y0
),
637 _cairo_fixed_from_double (matrix
->xx
),
638 _cairo_fixed_from_double (matrix
->yy
));
642 buf
= &path
->buf_head
.base
;
644 for (i
= 0; i
< buf
->num_points
; i
++) {
645 dx
= _cairo_fixed_to_double (buf
->points
[i
].x
);
646 dy
= _cairo_fixed_to_double (buf
->points
[i
].y
);
648 cairo_matrix_transform_point (matrix
, &dx
, &dy
);
650 buf
->points
[i
].x
= _cairo_fixed_from_double (dx
);
651 buf
->points
[i
].y
= _cairo_fixed_from_double (dy
);
659 _cairo_path_fixed_is_equal (cairo_path_fixed_t
*path
,
660 cairo_path_fixed_t
*other
)
662 cairo_path_buf_t
*path_buf
, *other_buf
;
664 if (path
->current_point
.x
!= other
->current_point
.x
||
665 path
->current_point
.y
!= other
->current_point
.y
||
666 path
->has_current_point
!= other
->has_current_point
||
667 path
->has_curve_to
!= other
->has_curve_to
||
668 path
->last_move_point
.x
!= other
->last_move_point
.x
||
669 path
->last_move_point
.y
!= other
->last_move_point
.y
)
672 other_buf
= &other
->buf_head
.base
;
673 for (path_buf
= &path
->buf_head
.base
;
675 path_buf
= path_buf
->next
)
677 if (other_buf
== NULL
||
678 path_buf
->num_ops
!= other_buf
->num_ops
||
679 path_buf
->num_points
!= other_buf
->num_points
||
680 memcmp (path_buf
->op
, other_buf
->op
,
681 sizeof (cairo_path_op_t
) * path_buf
->num_ops
) != 0 ||
682 memcmp (path_buf
->points
, other_buf
->points
,
683 sizeof (cairo_point_t
) * path_buf
->num_points
) != 0)
687 other_buf
= other_buf
->next
;
692 /* Closure for path flattening */
693 typedef struct cairo_path_flattener
{
695 cairo_point_t current_point
;
696 cairo_path_fixed_move_to_func_t
*move_to
;
697 cairo_path_fixed_line_to_func_t
*line_to
;
698 cairo_path_fixed_close_path_func_t
*close_path
;
702 static cairo_status_t
703 _cpf_move_to (void *closure
, cairo_point_t
*point
)
705 cpf_t
*cpf
= closure
;
707 cpf
->current_point
= *point
;
709 return cpf
->move_to (cpf
->closure
, point
);
712 static cairo_status_t
713 _cpf_line_to (void *closure
, cairo_point_t
*point
)
715 cpf_t
*cpf
= closure
;
717 cpf
->current_point
= *point
;
719 return cpf
->line_to (cpf
->closure
, point
);
722 static cairo_status_t
723 _cpf_curve_to (void *closure
,
728 cpf_t
*cpf
= closure
;
729 cairo_status_t status
;
730 cairo_spline_t spline
;
733 cairo_point_t
*p0
= &cpf
->current_point
;
735 status
= _cairo_spline_init (&spline
, p0
, p1
, p2
, p3
);
736 if (status
== CAIRO_INT_STATUS_DEGENERATE
)
737 return CAIRO_STATUS_SUCCESS
;
739 status
= _cairo_spline_decompose (&spline
, cpf
->tolerance
);
743 for (i
=1; i
< spline
.num_points
; i
++) {
744 status
= cpf
->line_to (cpf
->closure
, &spline
.points
[i
]);
749 cpf
->current_point
= *p3
;
751 status
= CAIRO_STATUS_SUCCESS
;
754 _cairo_spline_fini (&spline
);
758 static cairo_status_t
759 _cpf_close_path (void *closure
)
761 cpf_t
*cpf
= closure
;
763 return cpf
->close_path (cpf
->closure
);
768 _cairo_path_fixed_interpret_flat (const cairo_path_fixed_t
*path
,
769 cairo_direction_t dir
,
770 cairo_path_fixed_move_to_func_t
*move_to
,
771 cairo_path_fixed_line_to_func_t
*line_to
,
772 cairo_path_fixed_close_path_func_t
*close_path
,
778 flattener
.tolerance
= tolerance
;
779 flattener
.move_to
= move_to
;
780 flattener
.line_to
= line_to
;
781 flattener
.close_path
= close_path
;
782 flattener
.closure
= closure
;
783 return _cairo_path_fixed_interpret (path
, dir
,
792 _cairo_path_fixed_is_empty (cairo_path_fixed_t
*path
)
794 if (path
->buf_head
.base
.num_ops
== 0)
801 * Check whether the given path contains a single rectangle.
804 _cairo_path_fixed_is_box (cairo_path_fixed_t
*path
,
807 cairo_path_buf_t
*buf
= &path
->buf_head
.base
;
809 /* We can't have more than one buf for this check */
810 if (buf
->next
!= NULL
)
813 /* Do we have the right number of ops? */
814 if (buf
->num_ops
!= 5 && buf
->num_ops
!= 6)
817 /* Check whether the ops are those that would be used for a rectangle */
818 if (buf
->op
[0] != CAIRO_PATH_OP_MOVE_TO
||
819 buf
->op
[1] != CAIRO_PATH_OP_LINE_TO
||
820 buf
->op
[2] != CAIRO_PATH_OP_LINE_TO
||
821 buf
->op
[3] != CAIRO_PATH_OP_LINE_TO
)
826 /* Now, there are choices. The rectangle might end with a LINE_TO
827 * (to the original point), but this isn't required. If it
828 * doesn't, then it must end with a CLOSE_PATH. */
829 if (buf
->op
[4] == CAIRO_PATH_OP_LINE_TO
) {
830 if (buf
->points
[4].x
!= buf
->points
[0].x
||
831 buf
->points
[4].y
!= buf
->points
[0].y
)
833 } else if (buf
->op
[4] != CAIRO_PATH_OP_CLOSE_PATH
) {
837 if (buf
->num_ops
== 6) {
838 /* A trailing CLOSE_PATH or MOVE_TO is ok */
839 if (buf
->op
[5] != CAIRO_PATH_OP_MOVE_TO
&&
840 buf
->op
[5] != CAIRO_PATH_OP_CLOSE_PATH
)
844 /* Ok, we may have a box, if the points line up */
845 if (buf
->points
[0].y
== buf
->points
[1].y
&&
846 buf
->points
[1].x
== buf
->points
[2].x
&&
847 buf
->points
[2].y
== buf
->points
[3].y
&&
848 buf
->points
[3].x
== buf
->points
[0].x
)
851 box
->p1
= buf
->points
[0];
852 box
->p2
= buf
->points
[2];
857 if (buf
->points
[0].x
== buf
->points
[1].x
&&
858 buf
->points
[1].y
== buf
->points
[2].y
&&
859 buf
->points
[2].x
== buf
->points
[3].x
&&
860 buf
->points
[3].y
== buf
->points
[0].y
)
863 box
->p1
= buf
->points
[0];
864 box
->p2
= buf
->points
[2];
873 * Check whether the given path contains a single rectangle
874 * that is logically equivalent to:
875 * <informalexample><programlisting>
876 * cairo_move_to (cr, x, y);
877 * cairo_rel_line_to (cr, width, 0);
878 * cairo_rel_line_to (cr, 0, height);
879 * cairo_rel_line_to (cr, -width, 0);
880 * cairo_close_path (cr);
881 * </programlisting></informalexample>
884 _cairo_path_fixed_is_rectangle (cairo_path_fixed_t
*path
,
887 cairo_path_buf_t
*buf
= &path
->buf_head
.base
;
889 if (!_cairo_path_fixed_is_box (path
, box
))
892 if (buf
->points
[0].y
== buf
->points
[1].y
)