1 /**************************************************************************
3 * Copyright 2009 VMware, Inc. All Rights Reserved.
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the
7 * "Software"), to deal in the Software without restriction, including
8 * without limitation the rights to use, copy, modify, merge, publish,
9 * distribute, sub license, and/or sell copies of the Software, and to
10 * permit persons to whom the Software is furnished to do so, subject to
11 * the following conditions:
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial portions
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
20 * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
21 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 **************************************************************************/
33 #include "vg_context.h"
34 #include "util_array.h"
36 #include "path_utils.h"
40 #include "util/u_memory.h"
47 struct vg_object base
;
50 VGboolean dirty_stroke
;
52 VGPathDatatype datatype
;
59 struct array
* segments
;
60 struct array
* control_points
;
63 struct polygon_array polygon_array
;
73 VGJoinStyle join_style
;
78 static INLINE
void data_at(void **data
,
80 VGint start
, VGint count
,
83 VGPathDatatype dt
= p
->datatype
;
85 VGint end
= start
+ count
;
89 case VG_PATH_DATATYPE_S_8
: {
90 VGbyte
**bdata
= (VGbyte
**)data
;
91 for (i
= start
; i
< end
; ++i
) {
98 case VG_PATH_DATATYPE_S_16
: {
99 VGshort
**bdata
= (VGshort
**)data
;
100 for (i
= start
; i
< end
; ++i
) {
107 case VG_PATH_DATATYPE_S_32
: {
108 VGint
**bdata
= (VGint
**)data
;
109 for (i
= start
; i
< end
; ++i
) {
116 case VG_PATH_DATATYPE_F
: {
117 VGfloat
**fdata
= (VGfloat
**)data
;
118 for (i
= start
; i
< end
; ++i
) {
126 debug_assert(!"Unknown path datatype!");
131 void vg_float_to_datatype(VGPathDatatype datatype
,
132 VGubyte
*common_data
,
138 case VG_PATH_DATATYPE_S_8
: {
139 for (i
= 0; i
< num_coords
; ++i
) {
140 common_data
[i
] = (VGubyte
)data
[i
];
144 case VG_PATH_DATATYPE_S_16
: {
145 VGshort
*buf
= (VGshort
*)common_data
;
146 for (i
= 0; i
< num_coords
; ++i
) {
147 buf
[i
] = (VGshort
)data
[i
];
151 case VG_PATH_DATATYPE_S_32
: {
152 VGint
*buf
= (VGint
*)common_data
;
153 for (i
= 0; i
< num_coords
; ++i
) {
154 buf
[i
] = (VGint
)data
[i
];
158 case VG_PATH_DATATYPE_F
: {
159 memcpy(common_data
, data
, sizeof(VGfloat
) * num_coords
);
163 debug_assert(!"Unknown path datatype!");
167 static void coords_adjust_by_scale_bias(struct path
*p
,
168 void *pdata
, VGint num_coords
,
169 VGfloat scale
, VGfloat bias
,
170 VGPathDatatype datatype
)
173 void *coords
= (VGfloat
*)pdata
;
174 VGubyte
*common_data
= (VGubyte
*)pdata
;
175 VGint size_dst
= size_for_datatype(datatype
);
178 for (i
= 0; i
< num_coords
; ++i
) {
179 data_at(&coords
, p
, 0, 1, data
);
180 data
[0] = data
[0] * scale
+ bias
;
181 vg_float_to_datatype(datatype
, common_data
, data
, 1);
182 common_data
+= size_dst
;
186 struct path
* path_create(VGPathDatatype dt
, VGfloat scale
, VGfloat bias
,
187 VGint segmentCapacityHint
,
188 VGint coordCapacityHint
,
189 VGbitfield capabilities
)
191 struct path
*path
= CALLOC_STRUCT(path
);
193 vg_init_object(&path
->base
, vg_current_context(), VG_OBJECT_PATH
);
194 path
->caps
= capabilities
& VG_PATH_CAPABILITY_ALL
;
195 vg_context_add_object(vg_current_context(), VG_OBJECT_PATH
, path
);
201 path
->segments
= array_create(size_for_datatype(VG_PATH_DATATYPE_S_8
));
202 path
->control_points
= array_create(size_for_datatype(dt
));
204 path
->dirty
= VG_TRUE
;
205 path
->dirty_stroke
= VG_TRUE
;
210 void path_destroy(struct path
*p
)
212 vg_context_remove_object(vg_current_context(), VG_OBJECT_PATH
, p
);
214 array_destroy(p
->segments
);
215 array_destroy(p
->control_points
);
216 array_destroy(p
->fill_polys
.polygon_array
.array
);
219 path_destroy(p
->stroked
.path
);
224 VGbitfield
path_capabilities(struct path
*p
)
229 void path_set_capabilities(struct path
*p
, VGbitfield bf
)
231 p
->caps
= (bf
& VG_PATH_CAPABILITY_ALL
);
234 void path_append_data(struct path
*p
,
236 const VGubyte
* pathSegments
,
237 const void * pathData
)
239 VGint old_segments
= p
->num_segments
;
240 VGint num_new_coords
= num_elements_for_segments(pathSegments
, numSegments
);
241 array_append_data(p
->segments
, pathSegments
, numSegments
);
242 array_append_data(p
->control_points
, pathData
, num_new_coords
);
244 p
->num_segments
+= numSegments
;
245 if (!floatsEqual(p
->scale
, 1.f
) || !floatsEqual(p
->bias
, 0.f
)) {
246 VGubyte
*coords
= (VGubyte
*)p
->control_points
->data
;
247 coords_adjust_by_scale_bias(p
,
248 coords
+ old_segments
* p
->control_points
->datatype_size
,
250 p
->scale
, p
->bias
, p
->datatype
);
253 p
->dirty_stroke
= VG_TRUE
;
256 VGint
path_num_segments(struct path
*p
)
258 return p
->num_segments
;
261 static INLINE
void map_if_relative(VGfloat ox
, VGfloat oy
,
263 VGfloat
*x
, VGfloat
*y
)
273 static INLINE
void close_polygon(struct polygon
*current
,
274 VGfloat sx
, VGfloat sy
,
275 VGfloat ox
, VGfloat oy
,
276 struct matrix
*matrix
)
278 if (!floatsEqual(sx
, ox
) ||
279 !floatsEqual(sy
, oy
)) {
282 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
283 polygon_vertex_append(current
, x0
, y0
);
287 static void convert_path(struct path
*p
,
293 void *coords
= (VGfloat
*)p
->control_points
->data
;
294 VGubyte
*common_data
= (VGubyte
*)dst
;
295 VGint size_dst
= size_for_datatype(to
);
298 for (i
= 0; i
< num_coords
; ++i
) {
299 data_at(&coords
, p
, 0, 1, data
);
300 vg_float_to_datatype(to
, common_data
, data
, 1);
301 common_data
+= size_dst
;
306 static void polygon_array_calculate_bounds( struct polygon_array
*polyarray
)
308 struct array
*polys
= polyarray
->array
;
309 VGfloat min_x
, max_x
;
310 VGfloat min_y
, max_y
;
316 if (!polys
->num_elements
) {
317 polyarray
->min_x
= 0.0f
;
318 polyarray
->min_y
= 0.0f
;
319 polyarray
->max_x
= 0.0f
;
320 polyarray
->max_y
= 0.0f
;
324 polygon_bounding_rect((((struct polygon
**)polys
->data
)[0]), bounds
);
327 max_x
= bounds
[0] + bounds
[2];
328 max_y
= bounds
[1] + bounds
[3];
329 for (i
= 1; i
< polys
->num_elements
; ++i
) {
330 struct polygon
*p
= (((struct polygon
**)polys
->data
)[i
]);
331 polygon_bounding_rect(p
, bounds
);
332 min_x
= MIN2(min_x
, bounds
[0]);
333 min_y
= MIN2(min_y
, bounds
[1]);
334 max_x
= MAX2(max_x
, bounds
[0] + bounds
[2]);
335 max_y
= MAX2(max_y
, bounds
[1] + bounds
[3]);
338 polyarray
->min_x
= min_x
;
339 polyarray
->min_y
= min_y
;
340 polyarray
->max_x
= max_x
;
341 polyarray
->max_y
= max_y
;
345 static struct polygon_array
* path_get_fill_polygons(struct path
*p
, struct matrix
*matrix
)
348 struct polygon
*current
= 0;
349 VGfloat sx
, sy
, px
, py
, ox
, oy
;
350 VGfloat x0
, y0
, x1
, y1
, x2
, y2
, x3
, y3
;
352 void *coords
= (VGfloat
*)p
->control_points
->data
;
355 if (p
->fill_polys
.polygon_array
.array
)
357 if (memcmp( &p
->fill_polys
.matrix
,
359 sizeof *matrix
) == 0 && p
->dirty
== VG_FALSE
)
361 return &p
->fill_polys
.polygon_array
;
364 array_destroy( p
->fill_polys
.polygon_array
.array
);
365 p
->fill_polys
.polygon_array
.array
= NULL
;
369 array
= array_create(sizeof(struct array
*));
371 sx
= sy
= px
= py
= ox
= oy
= 0.f
;
374 current
= polygon_create(32);
376 for (i
= 0; i
< p
->num_segments
; ++i
) {
377 VGubyte segment
= ((VGubyte
*)(p
->segments
->data
))[i
];
378 VGint command
= SEGMENT_COMMAND(segment
);
379 VGboolean relative
= SEGMENT_ABS_REL(segment
);
383 close_polygon(current
, sx
, sy
, ox
, oy
, matrix
);
388 if (current
&& polygon_vertex_count(current
) > 0) {
390 close_polygon(current
, sx
, sy
, ox
, oy
, matrix
);
391 array_append_data(array
, ¤t
, 1);
392 current
= polygon_create(32);
394 data_at(&coords
, p
, 0, 2, data
);
397 map_if_relative(ox
, oy
, relative
, &x0
, &y0
);
404 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
405 polygon_vertex_append(current
, x0
, y0
);
408 data_at(&coords
, p
, 0, 2, data
);
411 map_if_relative(ox
, oy
, relative
, &x0
, &y0
);
416 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
417 polygon_vertex_append(current
, x0
, y0
);
420 data_at(&coords
, p
, 0, 1, data
);
423 map_if_relative(ox
, oy
, relative
, &x0
, 0);
427 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
428 polygon_vertex_append(current
, x0
, y0
);
431 data_at(&coords
, p
, 0, 1, data
);
434 map_if_relative(ox
, oy
, relative
, 0, &y0
);
438 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
439 polygon_vertex_append(current
, x0
, y0
);
442 struct bezier bezier
;
443 data_at(&coords
, p
, 0, 6, data
);
452 map_if_relative(ox
, oy
, relative
, &x1
, &y1
);
453 map_if_relative(ox
, oy
, relative
, &x2
, &y2
);
454 map_if_relative(ox
, oy
, relative
, &x3
, &y3
);
459 assert(matrix_is_affine(matrix
));
460 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
461 matrix_map_point(matrix
, x1
, y1
, &x1
, &y1
);
462 matrix_map_point(matrix
, x2
, y2
, &x2
, &y2
);
463 matrix_map_point(matrix
, x3
, y3
, &x3
, &y3
);
464 bezier_init(&bezier
, x0
, y0
, x1
, y1
,
466 bezier_add_to_polygon(&bezier
, current
);
470 struct bezier bezier
;
471 data_at(&coords
, p
, 0, 4, data
);
478 map_if_relative(ox
, oy
, relative
, &x1
, &y1
);
479 map_if_relative(ox
, oy
, relative
, &x3
, &y3
);
482 { /* form a cubic out of it */
483 x2
= (x3
+ 2*x1
) / 3.f
;
484 y2
= (y3
+ 2*y1
) / 3.f
;
485 x1
= (x0
+ 2*x1
) / 3.f
;
486 y1
= (y0
+ 2*y1
) / 3.f
;
490 assert(matrix_is_affine(matrix
));
491 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
492 matrix_map_point(matrix
, x1
, y1
, &x1
, &y1
);
493 matrix_map_point(matrix
, x2
, y2
, &x2
, &y2
);
494 matrix_map_point(matrix
, x3
, y3
, &x3
, &y3
);
495 bezier_init(&bezier
, x0
, y0
, x1
, y1
,
497 bezier_add_to_polygon(&bezier
, current
);
501 struct bezier bezier
;
502 data_at(&coords
, p
, 0, 2, data
);
509 map_if_relative(ox
, oy
, relative
, &x3
, &y3
);
512 { /* form a cubic out of it */
513 x2
= (x3
+ 2*x1
) / 3.f
;
514 y2
= (y3
+ 2*y1
) / 3.f
;
515 x1
= (x0
+ 2*x1
) / 3.f
;
516 y1
= (y0
+ 2*y1
) / 3.f
;
520 assert(matrix_is_affine(matrix
));
521 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
522 matrix_map_point(matrix
, x1
, y1
, &x1
, &y1
);
523 matrix_map_point(matrix
, x2
, y2
, &x2
, &y2
);
524 matrix_map_point(matrix
, x3
, y3
, &x3
, &y3
);
525 bezier_init(&bezier
, x0
, y0
, x1
, y1
,
527 bezier_add_to_polygon(&bezier
, current
);
531 struct bezier bezier
;
532 data_at(&coords
, p
, 0, 4, data
);
541 map_if_relative(ox
, oy
, relative
, &x2
, &y2
);
542 map_if_relative(ox
, oy
, relative
, &x3
, &y3
);
547 assert(matrix_is_affine(matrix
));
548 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
549 matrix_map_point(matrix
, x1
, y1
, &x1
, &y1
);
550 matrix_map_point(matrix
, x2
, y2
, &x2
, &y2
);
551 matrix_map_point(matrix
, x3
, y3
, &x3
, &y3
);
552 bezier_init(&bezier
, x0
, y0
, x1
, y1
,
554 bezier_add_to_polygon(&bezier
, current
);
564 data_at(&coords
, p
, 0, 5, data
);
572 map_if_relative(ox
, oy
, relative
, &x1
, &y1
);
574 debug_printf("------- ARC (%f, %f), (%f, %f) %f, %f, %f\n",
575 x0
, y0
, x1
, y1
, rh
, rv
, rot
);
577 arc_init(&arc
, command
, x0
, y0
, x1
, y1
,
579 arc_add_to_polygon(&arc
, current
,
589 assert(!"Unknown segment!");
593 if (polygon_vertex_count(current
) > 0) {
594 close_polygon(current
, sx
, sy
, ox
, oy
, matrix
);
595 array_append_data(array
, ¤t
, 1);
597 polygon_destroy(current
);
600 p
->fill_polys
.polygon_array
.array
= array
;
601 p
->fill_polys
.matrix
= *matrix
;
603 polygon_array_calculate_bounds( &p
->fill_polys
.polygon_array
);
607 return &p
->fill_polys
.polygon_array
;
610 VGbyte
path_datatype_size(struct path
*p
)
612 return size_for_datatype(p
->datatype
);
615 VGPathDatatype
path_datatype(struct path
*p
)
620 VGfloat
path_scale(struct path
*p
)
625 VGfloat
path_bias(struct path
*p
)
630 VGint
path_num_coords(struct path
*p
)
632 return num_elements_for_segments((VGubyte
*)p
->segments
->data
,
636 void path_modify_coords(struct path
*p
,
639 const void * pathData
)
641 VGubyte
*segments
= (VGubyte
*)(p
->segments
->data
);
642 VGint count
= num_elements_for_segments(&segments
[startIndex
], numSegments
);
643 VGint start_cp
= num_elements_for_segments(segments
, startIndex
);
645 array_change_data(p
->control_points
, pathData
, start_cp
, count
);
646 coords_adjust_by_scale_bias(p
,
647 ((VGubyte
*)p
->control_points
->data
) +
648 (startIndex
* p
->control_points
->datatype_size
),
650 p
->scale
, p
->bias
, p
->datatype
);
652 p
->dirty_stroke
= VG_TRUE
;
655 void path_for_each_segment(struct path
*path
,
660 struct path_for_each_data p
;
662 void *coords
= (VGfloat
*)path
->control_points
->data
;
665 p
.sx
= p
.sy
= p
.px
= p
.py
= p
.ox
= p
.oy
= 0.f
;
666 p
.user_data
= user_data
;
668 for (i
= 0; i
< path
->num_segments
; ++i
) {
672 p
.segment
= ((VGubyte
*)(path
->segments
->data
))[i
];
673 command
= SEGMENT_COMMAND(p
.segment
);
674 relative
= SEGMENT_ABS_REL(p
.segment
);
681 data_at(&coords
, path
, 0, 2, data
);
682 map_if_relative(p
.ox
, p
.oy
, relative
, &data
[0], &data
[1]);
692 data_at(&coords
, path
, 0, 2, data
);
693 map_if_relative(p
.ox
, p
.oy
, relative
, &data
[0], &data
[1]);
701 data_at(&coords
, path
, 0, 1, data
);
702 map_if_relative(p
.ox
, p
.oy
, relative
, &data
[0], 0);
703 p
.segment
= VG_LINE_TO
;
712 data_at(&coords
, path
, 0, 1, data
);
713 map_if_relative(p
.ox
, p
.oy
, relative
, 0, &data
[0]);
714 p
.segment
= VG_LINE_TO
;
724 data_at(&coords
, path
, 0, 6, data
);
725 map_if_relative(p
.ox
, p
.oy
, relative
, &data
[0], &data
[1]);
726 map_if_relative(p
.ox
, p
.oy
, relative
, &data
[2], &data
[3]);
727 map_if_relative(p
.ox
, p
.oy
, relative
, &data
[4], &data
[5]);
736 data_at(&coords
, path
, 0, 4, data
);
737 map_if_relative(p
.ox
, p
.oy
, relative
, &data
[0], &data
[1]);
738 map_if_relative(p
.ox
, p
.oy
, relative
, &data
[2], &data
[3]);
747 data_at(&coords
, path
, 0, 2, data
);
748 map_if_relative(p
.ox
, p
.oy
, relative
, &data
[0], &data
[1]);
757 data_at(&coords
, path
, 0, 4, data
);
758 map_if_relative(p
.ox
, p
.oy
, relative
, &data
[0], &data
[1]);
759 map_if_relative(p
.ox
, p
.oy
, relative
, &data
[2], &data
[3]);
771 data_at(&coords
, path
, 0, 5, data
);
772 map_if_relative(p
.ox
, p
.oy
, relative
, &data
[3], &data
[4]);
774 debug_printf("------- ARC (%f, %f), (%f, %f) %f, %f, %f\n",
775 p
.ox
, p
.oy
, data
[3], data
[4], data
[0], data
[1], data
[2]);
786 assert(!"Unknown segment!");
791 struct transform_data
{
792 struct array
*segments
;
793 struct array
*coords
;
795 struct matrix
*matrix
;
797 VGPathDatatype datatype
;
800 static VGboolean
transform_cb(struct path
*p
,
801 struct path_for_each_data
*pd
)
803 struct transform_data
*td
= (struct transform_data
*)pd
->user_data
;
804 VGint num_coords
= num_elements_for_segments(&pd
->segment
, 1);
805 VGubyte segment
= SEGMENT_COMMAND(pd
->segment
);/* abs bit is 0 */
807 VGubyte common_data
[sizeof(VGfloat
)*8];
809 memcpy(data
, pd
->coords
, sizeof(VGfloat
) * num_coords
);
815 matrix_map_point(td
->matrix
,
816 data
[0], data
[1], &data
[0], &data
[1]);
819 matrix_map_point(td
->matrix
,
820 data
[0], data
[1], &data
[0], &data
[1]);
827 matrix_map_point(td
->matrix
,
828 data
[0], data
[1], &data
[0], &data
[1]);
829 matrix_map_point(td
->matrix
,
830 data
[2], data
[3], &data
[2], &data
[3]);
833 matrix_map_point(td
->matrix
,
834 data
[0], data
[1], &data
[0], &data
[1]);
835 matrix_map_point(td
->matrix
,
836 data
[2], data
[3], &data
[2], &data
[3]);
837 matrix_map_point(td
->matrix
,
838 data
[4], data
[5], &data
[4], &data
[5]);
841 matrix_map_point(td
->matrix
,
842 data
[0], data
[1], &data
[0], &data
[1]);
845 matrix_map_point(td
->matrix
,
846 data
[0], data
[1], &data
[0], &data
[1]);
847 matrix_map_point(td
->matrix
,
848 data
[2], data
[3], &data
[2], &data
[3]);
855 struct path
*path
= path_create(td
->datatype
,
856 1, 0, 0, 0, VG_PATH_CAPABILITY_ALL
);
857 arc_init(&arc
, segment
,
858 pd
->ox
, pd
->oy
, data
[3], data
[4],
859 data
[0], data
[1], data
[2]);
861 arc_to_path(&arc
, path
, td
->matrix
);
863 num_coords
= path_num_coords(path
);
865 array_append_data(td
->segments
, path
->segments
->data
,
867 array_append_data(td
->coords
, path
->control_points
->data
,
878 vg_float_to_datatype(td
->datatype
, common_data
, data
, num_coords
);
880 array_append_data(td
->segments
, &pd
->segment
, 1);
881 array_append_data(td
->coords
, common_data
, num_coords
);
885 void path_transform(struct path
*dst
, struct path
*src
)
887 struct transform_data data
;
888 struct vg_context
*ctx
= dst
->base
.ctx
;
890 data
.segments
= dst
->segments
;
891 data
.coords
= dst
->control_points
;
892 data
.matrix
= &ctx
->state
.vg
.path_user_to_surface_matrix
;
893 data
.datatype
= dst
->datatype
;
895 path_for_each_segment(src
, transform_cb
, (void*)&data
);
897 dst
->num_segments
= dst
->segments
->num_elements
;
898 dst
->dirty
= VG_TRUE
;
899 dst
->dirty_stroke
= VG_TRUE
;
902 void path_append_path(struct path
*dst
,
905 VGint num_coords
= path_num_coords(src
);
906 void *dst_data
= malloc(size_for_datatype(dst
->datatype
) * num_coords
);
907 array_append_data(dst
->segments
,
910 convert_path(src
, dst
->datatype
,
911 dst_data
, num_coords
);
912 array_append_data(dst
->control_points
,
917 dst
->num_segments
+= src
->num_segments
;
918 dst
->dirty
= VG_TRUE
;
919 dst
->dirty_stroke
= VG_TRUE
;
922 static INLINE VGboolean
is_segment_arc(VGubyte segment
)
924 VGubyte scommand
= SEGMENT_COMMAND(segment
);
925 return (scommand
== VG_SCCWARC_TO
||
926 scommand
== VG_SCWARC_TO
||
927 scommand
== VG_LCCWARC_TO
||
928 scommand
== VG_LCWARC_TO
);
931 struct path_iter_data
{
935 VGfloat px
, py
, ox
, oy
, sx
, sy
;
937 static INLINE VGubyte
normalize_coords(struct path_iter_data
*pd
,
941 VGint command
= SEGMENT_COMMAND(pd
->segment
);
942 VGboolean relative
= SEGMENT_ABS_REL(pd
->segment
);
949 return VG_CLOSE_PATH
;
952 data_at(&pd
->coords
, pd
->path
, 0, 2, data
);
953 map_if_relative(pd
->ox
, pd
->oy
, relative
, &data
[0], &data
[1]);
961 return VG_MOVE_TO_ABS
;
964 data_at(&pd
->coords
, pd
->path
, 0, 2, data
);
965 map_if_relative(pd
->ox
, pd
->oy
, relative
, &data
[0], &data
[1]);
971 return VG_LINE_TO_ABS
;
974 data_at(&pd
->coords
, pd
->path
, 0, 1, data
);
975 map_if_relative(pd
->ox
, pd
->oy
, relative
, &data
[0], 0);
982 return VG_LINE_TO_ABS
;
985 data_at(&pd
->coords
, pd
->path
, 0, 1, data
);
986 map_if_relative(pd
->ox
, pd
->oy
, relative
, 0, &data
[0]);
994 return VG_LINE_TO_ABS
;
997 data_at(&pd
->coords
, pd
->path
, 0, 6, data
);
998 map_if_relative(pd
->ox
, pd
->oy
, relative
, &data
[0], &data
[1]);
999 map_if_relative(pd
->ox
, pd
->oy
, relative
, &data
[2], &data
[3]);
1000 map_if_relative(pd
->ox
, pd
->oy
, relative
, &data
[4], &data
[5]);
1006 return VG_CUBIC_TO_ABS
;
1010 VGfloat x0
, y0
, x1
, y1
, x2
, y2
, x3
, y3
;
1011 data_at(&pd
->coords
, pd
->path
, 0, 4, data
);
1018 map_if_relative(pd
->ox
, pd
->oy
, relative
, &x1
, &y1
);
1019 map_if_relative(pd
->ox
, pd
->oy
, relative
, &x3
, &y3
);
1022 { /* form a cubic out of it */
1023 x2
= (x3
+ 2*x1
) / 3.f
;
1024 y2
= (y3
+ 2*y1
) / 3.f
;
1025 x1
= (x0
+ 2*x1
) / 3.f
;
1026 y1
= (y0
+ 2*y1
) / 3.f
;
1037 return VG_CUBIC_TO_ABS
;
1041 VGfloat x0
, y0
, x1
, y1
, x2
, y2
, x3
, y3
;
1042 data_at(&pd
->coords
, pd
->path
, 0, 2, data
);
1045 x1
= 2 * pd
->ox
- pd
->px
;
1046 y1
= 2 * pd
->oy
- pd
->py
;
1049 map_if_relative(pd
->ox
, pd
->oy
, relative
, &x3
, &y3
);
1052 { /* form a cubic out of it */
1053 x2
= (x3
+ 2*x1
) / 3.f
;
1054 y2
= (y3
+ 2*y1
) / 3.f
;
1055 x1
= (x0
+ 2*x1
) / 3.f
;
1056 y1
= (y0
+ 2*y1
) / 3.f
;
1067 return VG_CUBIC_TO_ABS
;
1070 case VG_SCUBIC_TO
: {
1071 VGfloat x0
, y0
, x1
, y1
, x2
, y2
, x3
, y3
;
1072 data_at(&pd
->coords
, pd
->path
, 0, 4, data
);
1075 x1
= 2*pd
->ox
-pd
->px
;
1076 y1
= 2*pd
->oy
-pd
->py
;
1081 map_if_relative(pd
->ox
, pd
->oy
, relative
, &x2
, &y2
);
1082 map_if_relative(pd
->ox
, pd
->oy
, relative
, &x3
, &y3
);
1094 return VG_CUBIC_TO_ABS
;
1100 case VG_LCWARC_TO
: {
1101 data_at(&pd
->coords
, pd
->path
, 0, 5, data
);
1102 map_if_relative(pd
->ox
, pd
->oy
, relative
, &data
[3], &data
[4]);
1108 return command
| VG_ABSOLUTE
;
1113 assert(!"Unknown segment!");
1117 static void linearly_interpolate(VGfloat
*result
,
1118 const VGfloat
*start
,
1124 for (i
= 0; i
< number
; ++i
) {
1125 result
[i
] = start
[i
] + (end
[i
] - start
[i
]) * amount
;
1129 VGboolean
path_interpolate(struct path
*dst
,
1130 struct path
*start
, struct path
*end
,
1133 /* temporary path that we can discard if it will turn
1134 * out that start is not compatible with end */
1135 struct path
*res_path
= path_create(dst
->datatype
,
1139 VGfloat start_coords
[8];
1140 VGfloat end_coords
[8];
1142 VGubyte common_data
[sizeof(VGfloat
)*8];
1143 struct path_iter_data start_iter
, end_iter
;
1145 memset(&start_iter
, 0, sizeof(struct path_iter_data
));
1146 memset(&end_iter
, 0, sizeof(struct path_iter_data
));
1148 start_iter
.path
= start
;
1149 start_iter
.coords
= start
->control_points
->data
;
1150 end_iter
.path
= end
;
1151 end_iter
.coords
= end
->control_points
->data
;
1153 for (i
= 0; i
< start
->num_segments
; ++i
) {
1155 VGubyte ssegment
, esegment
;
1156 VGint snum_coords
, enum_coords
;
1157 start_iter
.segment
= ((VGubyte
*)(start
->segments
->data
))[i
];
1158 end_iter
.segment
= ((VGubyte
*)(end
->segments
->data
))[i
];
1160 ssegment
= normalize_coords(&start_iter
, &snum_coords
,
1162 esegment
= normalize_coords(&end_iter
, &enum_coords
,
1165 if (is_segment_arc(ssegment
)) {
1166 if (!is_segment_arc(esegment
)) {
1167 path_destroy(res_path
);
1174 } else if (is_segment_arc(esegment
)) {
1175 path_destroy(res_path
);
1178 else if (ssegment
!= esegment
) {
1179 path_destroy(res_path
);
1185 linearly_interpolate(results
, start_coords
, end_coords
,
1186 amount
, snum_coords
);
1187 vg_float_to_datatype(dst
->datatype
, common_data
, results
, snum_coords
);
1188 path_append_data(res_path
, 1, &segment
, common_data
);
1191 path_append_path(dst
, res_path
);
1192 path_destroy(res_path
);
1194 dst
->dirty
= VG_TRUE
;
1195 dst
->dirty_stroke
= VG_TRUE
;
1200 void path_clear(struct path
*p
, VGbitfield capabilities
)
1202 path_set_capabilities(p
, capabilities
);
1203 array_destroy(p
->segments
);
1204 array_destroy(p
->control_points
);
1205 p
->segments
= array_create(size_for_datatype(VG_PATH_DATATYPE_S_8
));
1206 p
->control_points
= array_create(size_for_datatype(p
->datatype
));
1207 p
->num_segments
= 0;
1209 p
->dirty_stroke
= VG_TRUE
;
1212 struct path
* path_create_stroke(struct path
*p
,
1213 struct matrix
*matrix
)
1216 VGfloat sx
, sy
, px
, py
, ox
, oy
;
1217 VGfloat x0
, y0
, x1
, y1
, x2
, y2
, x3
, y3
;
1219 void *coords
= (VGfloat
*)p
->control_points
->data
;
1220 int dashed
= (p
->base
.ctx
->state
.vg
.stroke
.dash_pattern_num
? 1 : 0);
1221 struct dash_stroker stroker
;
1222 struct vg_state
*vg_state
= &p
->base
.ctx
->state
.vg
;
1224 if (p
->stroked
.path
)
1226 /* ### compare the dash patterns to see if we can cache them.
1227 * for now we simply always bail out if the path is dashed.
1229 if (memcmp( &p
->stroked
.matrix
,
1231 sizeof *matrix
) == 0 &&
1232 !dashed
&& !p
->dirty_stroke
&&
1233 floatsEqual(p
->stroked
.stroke_width
, vg_state
->stroke
.line_width
.f
) &&
1234 floatsEqual(p
->stroked
.miter_limit
, vg_state
->stroke
.miter_limit
.f
) &&
1235 p
->stroked
.cap_style
== vg_state
->stroke
.cap_style
&&
1236 p
->stroked
.join_style
== vg_state
->stroke
.join_style
)
1238 return p
->stroked
.path
;
1241 path_destroy( p
->stroked
.path
);
1242 p
->stroked
.path
= NULL
;
1247 sx
= sy
= px
= py
= ox
= oy
= 0.f
;
1250 dash_stroker_init((struct stroker
*)&stroker
, vg_state
);
1252 stroker_init((struct stroker
*)&stroker
, vg_state
);
1254 stroker_begin((struct stroker
*)&stroker
);
1256 for (i
= 0; i
< p
->num_segments
; ++i
) {
1257 VGubyte segment
= ((VGubyte
*)(p
->segments
->data
))[i
];
1258 VGint command
= SEGMENT_COMMAND(segment
);
1259 VGboolean relative
= SEGMENT_ABS_REL(segment
);
1262 case VG_CLOSE_PATH
: {
1265 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
1266 stroker_line_to((struct stroker
*)&stroker
, x0
, y0
);
1270 data_at(&coords
, p
, 0, 2, data
);
1273 map_if_relative(ox
, oy
, relative
, &x0
, &y0
);
1280 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
1281 stroker_move_to((struct stroker
*)&stroker
, x0
, y0
);
1284 data_at(&coords
, p
, 0, 2, data
);
1287 map_if_relative(ox
, oy
, relative
, &x0
, &y0
);
1292 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
1293 stroker_line_to((struct stroker
*)&stroker
, x0
, y0
);
1296 data_at(&coords
, p
, 0, 1, data
);
1299 map_if_relative(ox
, oy
, relative
, &x0
, 0);
1303 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
1304 stroker_line_to((struct stroker
*)&stroker
, x0
, y0
);
1307 data_at(&coords
, p
, 0, 1, data
);
1310 map_if_relative(ox
, oy
, relative
, 0, &y0
);
1314 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
1315 stroker_line_to((struct stroker
*)&stroker
, x0
, y0
);
1318 data_at(&coords
, p
, 0, 6, data
);
1327 map_if_relative(ox
, oy
, relative
, &x1
, &y1
);
1328 map_if_relative(ox
, oy
, relative
, &x2
, &y2
);
1329 map_if_relative(ox
, oy
, relative
, &x3
, &y3
);
1330 if (floatsEqual(x1
, ox
) && floatsEqual(y1
, oy
) &&
1331 floatsEqual(x1
, x2
) && floatsEqual(y1
, y2
) &&
1332 floatsEqual(x2
, x3
) && floatsEqual(y2
, y3
)) {
1333 /*ignore the empty segment */
1335 } else if (floatsEqual(x3
, ox
) && floatsEqual(y3
, oy
)) {
1336 /* if dup vertex, emit a line */
1339 matrix_map_point(matrix
, x3
, y3
, &x3
, &y3
);
1340 stroker_line_to((struct stroker
*)&stroker
, x3
, y3
);
1347 assert(matrix_is_affine(matrix
));
1348 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
1349 matrix_map_point(matrix
, x1
, y1
, &x1
, &y1
);
1350 matrix_map_point(matrix
, x2
, y2
, &x2
, &y2
);
1351 matrix_map_point(matrix
, x3
, y3
, &x3
, &y3
);
1352 stroker_curve_to((struct stroker
*)&stroker
, x1
, y1
, x2
, y2
, x3
, y3
);
1356 data_at(&coords
, p
, 0, 4, data
);
1363 map_if_relative(ox
, oy
, relative
, &x1
, &y1
);
1364 map_if_relative(ox
, oy
, relative
, &x3
, &y3
);
1367 { /* form a cubic out of it */
1368 x2
= (x3
+ 2*x1
) / 3.f
;
1369 y2
= (y3
+ 2*y1
) / 3.f
;
1370 x1
= (x0
+ 2*x1
) / 3.f
;
1371 y1
= (y0
+ 2*y1
) / 3.f
;
1373 if (floatsEqual(x1
, ox
) && floatsEqual(y1
, oy
) &&
1374 floatsEqual(x1
, x2
) && floatsEqual(y1
, y2
) &&
1375 floatsEqual(x2
, x3
) && floatsEqual(y2
, y3
)) {
1376 /*ignore the empty segment */
1378 } else if (floatsEqual(x3
, ox
) && floatsEqual(y3
, oy
)) {
1379 /* if dup vertex, emit a line */
1382 matrix_map_point(matrix
, x3
, y3
, &x3
, &y3
);
1383 stroker_line_to((struct stroker
*)&stroker
, x3
, y3
);
1388 assert(matrix_is_affine(matrix
));
1389 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
1390 matrix_map_point(matrix
, x1
, y1
, &x1
, &y1
);
1391 matrix_map_point(matrix
, x2
, y2
, &x2
, &y2
);
1392 matrix_map_point(matrix
, x3
, y3
, &x3
, &y3
);
1393 stroker_curve_to((struct stroker
*)&stroker
, x1
, y1
, x2
, y2
, x3
, y3
);
1397 data_at(&coords
, p
, 0, 2, data
);
1404 map_if_relative(ox
, oy
, relative
, &x3
, &y3
);
1407 { /* form a cubic out of it */
1408 x2
= (x3
+ 2*x1
) / 3.f
;
1409 y2
= (y3
+ 2*y1
) / 3.f
;
1410 x1
= (x0
+ 2*x1
) / 3.f
;
1411 y1
= (y0
+ 2*y1
) / 3.f
;
1413 if (floatsEqual(x1
, ox
) && floatsEqual(y1
, oy
) &&
1414 floatsEqual(x1
, x2
) && floatsEqual(y1
, y2
) &&
1415 floatsEqual(x2
, x3
) && floatsEqual(y2
, y3
)) {
1416 /*ignore the empty segment */
1418 } else if (floatsEqual(x3
, ox
) && floatsEqual(y3
, oy
)) {
1419 /* if dup vertex, emit a line */
1422 matrix_map_point(matrix
, x3
, y3
, &x3
, &y3
);
1423 stroker_line_to((struct stroker
*)&stroker
, x3
, y3
);
1428 assert(matrix_is_affine(matrix
));
1429 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
1430 matrix_map_point(matrix
, x1
, y1
, &x1
, &y1
);
1431 matrix_map_point(matrix
, x2
, y2
, &x2
, &y2
);
1432 matrix_map_point(matrix
, x3
, y3
, &x3
, &y3
);
1433 stroker_curve_to((struct stroker
*)&stroker
, x1
, y1
, x2
, y2
, x3
, y3
);
1436 case VG_SCUBIC_TO
: {
1437 data_at(&coords
, p
, 0, 4, data
);
1446 map_if_relative(ox
, oy
, relative
, &x2
, &y2
);
1447 map_if_relative(ox
, oy
, relative
, &x3
, &y3
);
1448 if (floatsEqual(x1
, ox
) && floatsEqual(y1
, oy
) &&
1449 floatsEqual(x1
, x2
) && floatsEqual(y1
, y2
) &&
1450 floatsEqual(x2
, x3
) && floatsEqual(y2
, y3
)) {
1451 /*ignore the empty segment */
1453 } else if (floatsEqual(x3
, ox
) && floatsEqual(y3
, oy
)) {
1454 /* if dup vertex, emit a line */
1457 matrix_map_point(matrix
, x3
, y3
, &x3
, &y3
);
1458 stroker_line_to((struct stroker
*)&stroker
, x3
, y3
);
1465 assert(matrix_is_affine(matrix
));
1466 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
1467 matrix_map_point(matrix
, x1
, y1
, &x1
, &y1
);
1468 matrix_map_point(matrix
, x2
, y2
, &x2
, &y2
);
1469 matrix_map_point(matrix
, x3
, y3
, &x3
, &y3
);
1470 stroker_curve_to((struct stroker
*)&stroker
, x1
, y1
, x2
, y2
, x3
, y3
);
1476 case VG_LCWARC_TO
: {
1477 VGfloat rh
, rv
, rot
;
1480 data_at(&coords
, p
, 0, 5, data
);
1488 map_if_relative(ox
, oy
, relative
, &x1
, &y1
);
1489 if (floatsEqual(x1
, ox
) && floatsEqual(y1
, oy
)) {
1490 /* if dup vertex, emit a line */
1493 matrix_map_point(matrix
, x1
, y1
, &x1
, &y1
);
1494 stroker_line_to((struct stroker
*)&stroker
, x1
, y1
);
1497 arc_init(&arc
, command
, x0
, y0
, x1
, y1
,
1499 arc_stroke_cb(&arc
, (struct stroker
*)&stroker
,
1509 assert(!"Unknown segment!");
1513 stroker_end((struct stroker
*)&stroker
);
1516 dash_stroker_cleanup((struct dash_stroker
*)&stroker
);
1518 stroker_cleanup((struct stroker
*)&stroker
);
1520 p
->stroked
.path
= stroker
.base
.path
;
1521 p
->stroked
.matrix
= *matrix
;
1522 p
->dirty_stroke
= VG_FALSE
;
1523 p
->stroked
.stroke_width
= vg_state
->stroke
.line_width
.f
;
1524 p
->stroked
.miter_limit
= vg_state
->stroke
.miter_limit
.f
;
1525 p
->stroked
.cap_style
= vg_state
->stroke
.cap_style
;
1526 p
->stroked
.join_style
= vg_state
->stroke
.join_style
;
1528 return stroker
.base
.path
;
1531 void path_render(struct path
*p
, VGbitfield paintModes
,
1534 struct vg_context
*ctx
= vg_current_context();
1536 vg_validate_state(ctx
);
1538 shader_set_drawing_image(ctx
->shader
, VG_FALSE
);
1539 shader_set_image(ctx
->shader
, 0);
1541 fprintf(stderr
, "Matrix(11=%f 12=%f 13=%f 21=%f 22=%f 23=%f 31=%f 32=%f 33=%f)\n",
1542 mat
->m
[0], mat
->m
[1], mat
->m
[2],
1543 mat
->m
[3], mat
->m
[4], mat
->m
[5],
1544 mat
->m
[6], mat
->m
[7], mat
->m
[8]);
1546 if (paintModes
& VG_FILL_PATH
) {
1547 /* First the fill */
1548 shader_set_paint(ctx
->shader
, ctx
->state
.vg
.fill_paint
);
1549 shader_bind(ctx
->shader
);
1553 if (paintModes
& VG_STROKE_PATH
){
1554 /* 8.7.5: "line width less than or equal to 0 prevents stroking from
1556 if (ctx
->state
.vg
.stroke
.line_width
.f
<= 0)
1558 shader_set_paint(ctx
->shader
, ctx
->state
.vg
.stroke_paint
);
1559 shader_bind(ctx
->shader
);
1560 path_stroke(p
, mat
);
1564 void path_fill(struct path
*p
, struct matrix
*mat
)
1566 struct vg_context
*ctx
= vg_current_context();
1568 struct polygon_array
*polygon_array
= path_get_fill_polygons(p
, mat
);
1569 struct array
*polys
= polygon_array
->array
;
1571 if (!polygon_array
|| !polys
|| !polys
->num_elements
) {
1574 polygon_array_fill(polygon_array
, ctx
);
1578 void path_stroke(struct path
*p
, struct matrix
*mat
)
1580 struct vg_context
*ctx
= vg_current_context();
1581 VGFillRule old_fill
= ctx
->state
.vg
.fill_rule
;
1582 struct matrix identity
;
1583 struct path
*stroke
;
1585 matrix_load_identity(&identity
);
1586 stroke
= path_create_stroke(p
, &identity
);
1587 if (stroke
&& !path_is_empty(stroke
)) {
1588 ctx
->state
.vg
.fill_rule
= VG_NON_ZERO
;
1590 path_fill(stroke
, mat
);
1592 ctx
->state
.vg
.fill_rule
= old_fill
;
1596 void path_move_to(struct path
*p
, float x
, float y
)
1598 VGubyte segment
= VG_MOVE_TO_ABS
;
1599 VGubyte common_data
[sizeof(VGfloat
) * 2];
1600 VGfloat data
[2] = {x
, y
};
1602 vg_float_to_datatype(p
->datatype
, common_data
, data
, 2);
1603 path_append_data(p
, 1, &segment
, common_data
);
1606 void path_line_to(struct path
*p
, float x
, float y
)
1608 VGubyte segment
= VG_LINE_TO_ABS
;
1609 VGubyte common_data
[sizeof(VGfloat
) * 2];
1610 VGfloat data
[2] = {x
, y
};
1612 vg_float_to_datatype(p
->datatype
, common_data
, data
, 2);
1614 path_append_data(p
, 1, &segment
, common_data
);
1617 void path_cubic_to(struct path
*p
, float px1
, float py1
,
1618 float px2
, float py2
,
1621 VGubyte segment
= VG_CUBIC_TO_ABS
;
1622 VGubyte common_data
[sizeof(VGfloat
) * 6];
1625 data
[0] = px1
; data
[1] = py1
;
1626 data
[2] = px2
; data
[3] = py2
;
1627 data
[4] = x
; data
[5] = y
;
1629 vg_float_to_datatype(p
->datatype
, common_data
, data
, 6);
1631 path_append_data(p
, 1, &segment
, common_data
);
1634 static INLINE
void line_bounds(VGfloat
*line
/*x1,y1,x2,y2*/,
1637 bounds
[0] = MIN2(line
[0], line
[2]);
1638 bounds
[1] = MIN2(line
[1], line
[3]);
1639 bounds
[2] = MAX2(line
[0], line
[2]) - bounds
[0];
1640 bounds
[3] = MAX2(line
[1], line
[3]) - bounds
[1];
1643 static INLINE
void unite_bounds(VGfloat
*bounds
,
1646 VGfloat cx1
, cy1
, cx2
, cy2
;
1647 VGfloat nx1
, ny1
, nx2
, ny2
;
1651 cx2
= bounds
[0] + bounds
[2];
1652 cy2
= bounds
[1] + bounds
[3];
1656 nx2
= el
[0] + el
[2];
1657 ny2
= el
[1] + el
[3];
1659 bounds
[0] = MIN2(cx1
, nx1
);
1660 bounds
[1] = MIN2(cy1
, ny1
);
1661 bounds
[2] = MAX2(cx2
, nx2
) - bounds
[0];
1662 bounds
[3] = MAX2(cy2
, ny2
) - bounds
[1];
1665 static INLINE
void set_bounds(VGfloat
*bounds
,
1666 VGfloat
*element_bounds
,
1667 VGboolean
*initialized
)
1669 if (!(*initialized
)) {
1670 memcpy(bounds
, element_bounds
, 4 * sizeof(VGfloat
));
1671 *initialized
= VG_TRUE
;
1673 unite_bounds(bounds
, element_bounds
);
1676 void path_bounding_rect(struct path
*p
, float *x
, float *y
,
1681 struct path_iter_data iter
;
1684 VGfloat element_bounds
[4];
1686 VGboolean bounds_inited
= VG_FALSE
;
1688 memset(&iter
, 0, sizeof(struct path_iter_data
));
1689 memset(&bounds
, 0, sizeof(bounds
));
1691 if (!p
->num_segments
) {
1698 iter
.coords
= p
->control_points
->data
;
1700 for (i
= 0; i
< p
->num_segments
; ++i
) {
1702 iter
.segment
= ((VGubyte
*)(p
->segments
->data
))[i
];
1707 segment
= normalize_coords(&iter
, &num_coords
, coords
);
1711 case VG_MOVE_TO_ABS
:
1713 case VG_LINE_TO_ABS
: {
1714 VGfloat line
[4] = {ox
, oy
, coords
[0], coords
[1]};
1715 line_bounds(line
, element_bounds
);
1716 set_bounds(bounds
, element_bounds
, &bounds_inited
);
1719 case VG_CUBIC_TO_ABS
: {
1720 struct bezier bezier
;
1721 bezier_init(&bezier
, ox
, oy
,
1722 coords
[0], coords
[1],
1723 coords
[2], coords
[3],
1724 coords
[4], coords
[5]);
1725 bezier_exact_bounds(&bezier
, element_bounds
);
1726 set_bounds(bounds
, element_bounds
, &bounds_inited
);
1732 case VG_LCWARC_TO
: {
1734 struct matrix identity
;
1735 struct path
*path
= path_create(VG_PATH_DATATYPE_F
,
1736 1, 0, 0, 0, VG_PATH_CAPABILITY_ALL
);
1738 matrix_load_identity(&identity
);
1739 arc_init(&arc
, segment
,
1740 ox
, oy
, coords
[3], coords
[4],
1741 coords
[0], coords
[1], coords
[2]);
1743 arc_to_path(&arc
, path
, &identity
);
1745 path_bounding_rect(path
, element_bounds
+ 0, element_bounds
+ 1,
1746 element_bounds
+ 2, element_bounds
+ 3);
1747 set_bounds(bounds
, element_bounds
, &bounds_inited
);
1761 float path_length(struct path
*p
, int start_segment
, int num_segments
)
1765 struct path_iter_data iter
;
1769 VGboolean in_range
= VG_FALSE
;
1771 memset(&iter
, 0, sizeof(struct path_iter_data
));
1774 iter
.coords
= p
->control_points
->data
;
1776 for (i
= 0; i
< (start_segment
+ num_segments
); ++i
) {
1779 iter
.segment
= ((VGubyte
*)(p
->segments
->data
))[i
];
1784 segment
= normalize_coords(&iter
, &num_coords
, coords
);
1786 in_range
= (i
>= start_segment
) && i
<= (start_segment
+ num_segments
);
1791 case VG_MOVE_TO_ABS
:
1793 case VG_CLOSE_PATH
: {
1794 VGfloat line
[4] = {ox
, oy
, iter
.sx
, iter
.sy
};
1795 length
+= line_lengthv(line
);
1798 case VG_LINE_TO_ABS
: {
1799 VGfloat line
[4] = {ox
, oy
, coords
[0], coords
[1]};
1800 length
+= line_lengthv(line
);
1803 case VG_CUBIC_TO_ABS
: {
1804 struct bezier bezier
;
1805 bezier_init(&bezier
, ox
, oy
,
1806 coords
[0], coords
[1],
1807 coords
[2], coords
[3],
1808 coords
[4], coords
[5]);
1809 length
+= bezier_length(&bezier
, BEZIER_DEFAULT_ERROR
);
1815 case VG_LCWARC_TO
: {
1817 struct matrix identity
;
1818 struct path
*path
= path_create(VG_PATH_DATATYPE_F
,
1819 1, 0, 0, 0, VG_PATH_CAPABILITY_ALL
);
1821 matrix_load_identity(&identity
);
1822 arc_init(&arc
, segment
,
1823 ox
, oy
, coords
[3], coords
[4],
1824 coords
[0], coords
[1], coords
[2]);
1826 arc_to_path(&arc
, path
, &identity
);
1828 length
+= path_length(path
, 0, path_num_segments(path
));
1839 static INLINE VGboolean
point_on_current_segment(VGfloat distance
,
1841 VGfloat segment_length
)
1844 (((floatIsZero(distance
) || distance
< 0) && floatIsZero(length
)) ||
1845 ((distance
> length
|| floatsEqual(distance
, length
)) &&
1846 (floatsEqual(distance
, length
+ segment_length
) ||
1847 distance
< (length
+ segment_length
))));
1850 static VGboolean
path_point_segment(struct path_iter_data iter
,
1851 struct path_iter_data prev_iter
,
1854 VGfloat length
, VGfloat
*current_length
,
1855 VGfloat
*point
, VGfloat
*normal
)
1857 switch (iter
.segment
) {
1858 case VG_MOVE_TO_ABS
:
1860 case VG_CLOSE_PATH
: {
1861 VGfloat line
[4] = {prev_iter
.ox
, prev_iter
.oy
, iter
.sx
, iter
.sy
};
1862 VGboolean on_current_segment
= VG_FALSE
;
1863 *current_length
= line_lengthv(line
);
1864 on_current_segment
= point_on_current_segment(distance
,
1867 if (on_current_segment
) {
1868 VGfloat at
= (distance
- length
) / line_lengthv(line
);
1869 line_normal_vector(line
, normal
);
1870 line_point_at(line
, at
, point
);
1875 case VG_LINE_TO_ABS
: {
1876 VGfloat line
[4] = {prev_iter
.ox
, prev_iter
.oy
, coords
[0], coords
[1]};
1877 VGboolean on_current_segment
= VG_FALSE
;
1878 *current_length
= line_lengthv(line
);
1879 on_current_segment
= point_on_current_segment(distance
,
1882 if (on_current_segment
) {
1883 VGfloat at
= (distance
- length
) / line_lengthv(line
);
1884 line_normal_vector(line
, normal
);
1885 line_point_at(line
, at
, point
);
1890 case VG_CUBIC_TO_ABS
: {
1891 struct bezier bezier
;
1892 bezier_init(&bezier
, prev_iter
.ox
, prev_iter
.oy
,
1893 coords
[0], coords
[1],
1894 coords
[2], coords
[3],
1895 coords
[4], coords
[5]);
1896 *current_length
= bezier_length(&bezier
, BEZIER_DEFAULT_ERROR
);
1897 if (point_on_current_segment(distance
, length
, *current_length
)) {
1898 bezier_point_at_length(&bezier
, distance
- length
,
1907 case VG_LCWARC_TO
: {
1909 struct matrix identity
;
1910 struct path
*path
= path_create(VG_PATH_DATATYPE_F
,
1911 1, 0, 0, 0, VG_PATH_CAPABILITY_ALL
);
1913 matrix_load_identity(&identity
);
1914 arc_init(&arc
, iter
.segment
,
1915 prev_iter
.ox
, prev_iter
.oy
, coords
[3], coords
[4],
1916 coords
[0], coords
[1], coords
[2]);
1918 arc_to_path(&arc
, path
, &identity
);
1920 *current_length
= path_length(path
, 0, path_num_segments(path
));
1921 if (point_on_current_segment(distance
, length
, *current_length
)) {
1922 path_point(path
, 0, path_num_segments(path
),
1923 distance
- length
, point
, normal
);
1934 void path_point(struct path
*p
, VGint start_segment
, VGint num_segments
,
1935 VGfloat distance
, VGfloat
*point
, VGfloat
*normal
)
1939 struct path_iter_data iter
, prev_iter
;
1942 VGfloat current_length
= 0;
1944 memset(&iter
, 0, sizeof(struct path_iter_data
));
1945 memset(&prev_iter
, 0, sizeof(struct path_iter_data
));
1954 iter
.coords
= p
->control_points
->data
;
1958 for (i
= 0; i
< (start_segment
+ num_segments
); ++i
) {
1959 VGboolean outside_range
= (i
< start_segment
||
1960 i
>= (start_segment
+ num_segments
));
1964 iter
.segment
= ((VGubyte
*)(p
->segments
->data
))[i
];
1965 iter
.segment
= normalize_coords(&iter
, &num_coords
, coords
);
1970 if (path_point_segment(iter
, prev_iter
, coords
,
1971 distance
, length
, ¤t_length
,
1975 length
+= current_length
;
1979 *OpenVG 1.0 - 8.6.11 vgPointAlongPath
1981 * If distance is greater than or equal to the path length
1982 *(i.e., the value returned by vgPathLength when called with the same
1983 *startSegment and numSegments parameters), the visual ending point of
1987 switch (iter
.segment
) {
1988 case VG_MOVE_TO_ABS
:
1990 case VG_CLOSE_PATH
: {
1991 VGfloat line
[4] = {prev_iter
.ox
, prev_iter
.oy
, iter
.sx
, iter
.sy
};
1992 line_normal_vector(line
, normal
);
1993 line_point_at(line
, 1.f
, point
);
1996 case VG_LINE_TO_ABS
: {
1997 VGfloat line
[4] = {prev_iter
.ox
, prev_iter
.oy
, coords
[0], coords
[1]};
1998 line_normal_vector(line
, normal
);
1999 line_point_at(line
, 1.f
, point
);
2002 case VG_CUBIC_TO_ABS
: {
2003 struct bezier bezier
;
2004 bezier_init(&bezier
, prev_iter
.ox
, prev_iter
.oy
,
2005 coords
[0], coords
[1],
2006 coords
[2], coords
[3],
2007 coords
[4], coords
[5]);
2008 bezier_point_at_t(&bezier
, 1.f
, point
, normal
);
2014 case VG_LCWARC_TO
: {
2016 struct matrix identity
;
2017 struct path
*path
= path_create(VG_PATH_DATATYPE_F
,
2018 1, 0, 0, 0, VG_PATH_CAPABILITY_ALL
);
2020 matrix_load_identity(&identity
);
2021 arc_init(&arc
, iter
.segment
,
2022 prev_iter
.ox
, prev_iter
.oy
, coords
[3], coords
[4],
2023 coords
[0], coords
[1], coords
[2]);
2025 arc_to_path(&arc
, path
, &identity
);
2027 path_point(path
, 0, path_num_segments(path
),
2028 /* to make sure we're bigger than len * 2 it */
2029 2 * path_length(path
, 0, path_num_segments(path
)),
2039 VGboolean
path_is_empty(struct path
*p
)
2041 return p
->segments
->num_elements
== 0;