1 /* CPML - Cairo Path Manipulation Library
2 * Copyright (C) 2008, Nicola Fontana <ntd at entidi.it>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
21 #include "cpml-segment.h"
22 #include "cpml-alloca.h"
27 static cairo_bool_t
normalize_segment (CpmlSegment
*segment
);
32 * @segment: a #CpmlSegment
33 * @src: the source cairo_path_t
35 * Builds a CpmlSegment from a cairo_path_t structure. This operation
36 * involves stripping the leading %MOVE_TO primitives and setting the
37 * internal segment structure accordling. A pointer to the source
38 * path segment is kept.
40 * Return value: 1 on success, 0 on errors
43 cpml_segment_init(CpmlSegment
*segment
, cairo_path_t
*src
)
45 /* The cairo path should be defined and in perfect state */
46 if (src
== NULL
|| src
->num_data
== 0 ||
47 src
->status
!= CAIRO_STATUS_SUCCESS
)
50 segment
->original
= src
;
51 memcpy(&segment
->path
, src
, sizeof(cairo_path_t
));
53 return normalize_segment(segment
);
58 * @segment: a #CpmlSegment
59 * @src: the source segment to copy
61 * Makes a shallow copy of @src into @segment.
63 * Return value: @segment or %NULL on errors
66 cpml_segment_copy(CpmlSegment
*segment
, const CpmlSegment
*src
)
68 if (segment
== NULL
|| src
== NULL
)
71 return memcpy(segment
, src
, sizeof(CpmlSegment
));
76 * @segment: a #CpmlSegment
78 * Dumps the specified @segment to stdout. Useful for debugging purposes.
81 cpml_segment_dump(const CpmlSegment
*segment
)
83 const cairo_path_t
*path
;
84 cairo_path_data_t
*data
;
87 if (segment
== NULL
) {
88 printf("Trying to dump a NULL segment!\n");
92 path
= &segment
->path
;
93 for (n_data
= 0; n_data
< path
->num_data
; ++n_data
) {
94 data
= path
->data
+ n_data
;
96 switch (data
->header
.type
) {
97 case CAIRO_PATH_MOVE_TO
:
100 case CAIRO_PATH_LINE_TO
:
103 case CAIRO_PATH_CURVE_TO
:
106 case CAIRO_PATH_CLOSE_PATH
:
107 printf("Path close");
110 printf("Unknown entity (%d)", data
->header
.type
);
114 for (n_point
= 1; n_point
< data
->header
.length
; ++n_point
)
115 printf("(%lf, %lf) ", data
[n_point
].point
.x
,
116 data
[n_point
].point
.y
);
118 n_data
+= n_point
- 1;
124 * cpml_segment_reset:
125 * @segment: a #CpmlSegment
127 * Modifies @segment to point to the first segment of the original path.
130 cpml_segment_reset(CpmlSegment
*segment
)
132 memcpy(&segment
->path
, segment
->original
, sizeof(cairo_path_t
));
133 normalize_segment(segment
);
138 * @segment: a #CpmlSegment
140 * Modifies @segment to point to the next segment of the original path.
142 * Return value: 1 on success, 0 if no next segment found or errors
145 cpml_segment_next(CpmlSegment
*segment
)
147 int num_data
= segment
->path
.num_data
;
148 int offset
= segment
->path
.data
- segment
->original
->data
;
150 segment
->path
.num_data
= segment
->original
->num_data
- num_data
- offset
;
151 segment
->path
.data
+= num_data
;
153 return normalize_segment(segment
);
157 * cpml_segment_reverse:
158 * @segment: a #CpmlSegment
160 * Reverses @segment in-place. The resulting rendering will be the same,
161 * but with the primitives generated in reverse order.
164 cpml_segment_reverse(CpmlSegment
*segment
)
166 cairo_path_data_t
*data
, *dst_data
;
169 int num_data
, n_data
;
170 int num_points
, n_point
;
171 const cairo_path_data_t
*src_data
;
173 num_data
= segment
->path
.num_data
;
174 data_size
= sizeof(cairo_path_data_t
) * num_data
;
175 data
= cpml_alloca(data_size
);
176 end_x
= segment
->path
.data
[1].point
.x
;
177 end_y
= segment
->path
.data
[1].point
.y
;
179 for (n_data
= 2; n_data
< num_data
; ++n_data
) {
180 src_data
= segment
->path
.data
+ n_data
;
181 num_points
= src_data
->header
.length
;
183 dst_data
= data
+ num_data
- n_data
- num_points
+ 2;
184 dst_data
->header
.type
= src_data
->header
.type
;
185 dst_data
->header
.length
= num_points
;
187 for (n_point
= 1; n_point
< num_points
; ++n_point
) {
188 dst_data
[num_points
- n_point
].point
.x
= end_x
;
189 dst_data
[num_points
- n_point
].point
.y
= end_y
;
190 end_x
= src_data
[n_point
].point
.x
;
191 end_y
= src_data
[n_point
].point
.y
;
194 n_data
+= n_point
- 1;
197 data
[0].header
.type
= CAIRO_PATH_MOVE_TO
;
198 data
[0].header
.length
= 2;
199 data
[1].point
.x
= end_x
;
200 data
[1].point
.y
= end_y
;
201 memcpy(segment
->path
.data
, data
, data_size
);
205 * cpml_segment_transform:
206 * @segment: a #CpmlSegment
207 * @matrix: the matrix to be applied
209 * Applies @matrix on all the points of @segment.
212 cpml_segment_transform(CpmlSegment
*segment
, const cairo_matrix_t
*matrix
)
214 cairo_path_data_t
*data
;
215 int n_data
, num_data
;
216 int n_point
, num_points
;
218 data
= segment
->path
.data
;
219 num_data
= segment
->path
.num_data
;
221 for (n_data
= 0; n_data
< num_data
; n_data
+= num_points
) {
222 num_points
= data
->header
.length
;
224 for (n_point
= 1; n_point
< num_points
; ++n_point
) {
225 cairo_matrix_transform_point(matrix
, &data
->point
.x
, &data
->point
.y
);
233 * @segment: a #CpmlSegment
235 * Strips the leading CAIRO_PATH_MOVE_TO primitives, updating the CpmlSegment
236 * structure accordling. One, and only once, MOVE_TO primitive is left.
238 * Return value: 1 on success, 0 on no leading MOVE_TOs or on errors
241 normalize_segment(CpmlSegment
*segment
)
243 cairo_path_data_t
*data
;
245 if (segment
== NULL
|| segment
->path
.num_data
<= 0)
248 data
= segment
->path
.data
;
249 if (data
->header
.type
!= CAIRO_PATH_MOVE_TO
) {
250 segment
->path
.status
= CAIRO_STATUS_INVALID_PATH_DATA
;
254 while (segment
->path
.num_data
>= 0) {
256 if (data
->header
.type
!= CAIRO_PATH_MOVE_TO
)
259 segment
->path
.data
= data
;
260 segment
->path
.num_data
-= 2;