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();
1535 struct matrix paint_matrix
;
1537 vg_validate_state(ctx
);
1539 shader_set_drawing_image(ctx
->shader
, VG_FALSE
);
1540 shader_set_image(ctx
->shader
, 0);
1542 fprintf(stderr
, "Matrix(11=%f 12=%f 13=%f 21=%f 22=%f 23=%f 31=%f 32=%f 33=%f)\n",
1543 mat
->m
[0], mat
->m
[1], mat
->m
[2],
1544 mat
->m
[3], mat
->m
[4], mat
->m
[5],
1545 mat
->m
[6], mat
->m
[7], mat
->m
[8]);
1547 if ((paintModes
& VG_FILL_PATH
) &&
1548 vg_get_paint_matrix(ctx
,
1549 &ctx
->state
.vg
.fill_paint_to_user_matrix
,
1552 /* First the fill */
1553 shader_set_paint(ctx
->shader
, ctx
->state
.vg
.fill_paint
);
1554 shader_set_paint_matrix(ctx
->shader
, &paint_matrix
);
1555 shader_bind(ctx
->shader
);
1559 if ((paintModes
& VG_STROKE_PATH
) &&
1560 vg_get_paint_matrix(ctx
,
1561 &ctx
->state
.vg
.stroke_paint_to_user_matrix
,
1564 /* 8.7.5: "line width less than or equal to 0 prevents stroking from
1566 if (ctx
->state
.vg
.stroke
.line_width
.f
<= 0)
1568 shader_set_paint(ctx
->shader
, ctx
->state
.vg
.stroke_paint
);
1569 shader_set_paint_matrix(ctx
->shader
, &paint_matrix
);
1570 shader_bind(ctx
->shader
);
1571 path_stroke(p
, mat
);
1575 void path_fill(struct path
*p
, struct matrix
*mat
)
1577 struct vg_context
*ctx
= vg_current_context();
1579 struct polygon_array
*polygon_array
= path_get_fill_polygons(p
, mat
);
1580 struct array
*polys
= polygon_array
->array
;
1582 if (!polygon_array
|| !polys
|| !polys
->num_elements
) {
1585 polygon_array_fill(polygon_array
, ctx
);
1589 void path_stroke(struct path
*p
, struct matrix
*mat
)
1591 struct vg_context
*ctx
= vg_current_context();
1592 VGFillRule old_fill
= ctx
->state
.vg
.fill_rule
;
1593 struct matrix identity
;
1594 struct path
*stroke
;
1596 matrix_load_identity(&identity
);
1597 stroke
= path_create_stroke(p
, &identity
);
1598 if (stroke
&& !path_is_empty(stroke
)) {
1599 ctx
->state
.vg
.fill_rule
= VG_NON_ZERO
;
1601 path_fill(stroke
, mat
);
1603 ctx
->state
.vg
.fill_rule
= old_fill
;
1607 void path_move_to(struct path
*p
, float x
, float y
)
1609 VGubyte segment
= VG_MOVE_TO_ABS
;
1610 VGubyte common_data
[sizeof(VGfloat
) * 2];
1611 VGfloat data
[2] = {x
, y
};
1613 vg_float_to_datatype(p
->datatype
, common_data
, data
, 2);
1614 path_append_data(p
, 1, &segment
, common_data
);
1617 void path_line_to(struct path
*p
, float x
, float y
)
1619 VGubyte segment
= VG_LINE_TO_ABS
;
1620 VGubyte common_data
[sizeof(VGfloat
) * 2];
1621 VGfloat data
[2] = {x
, y
};
1623 vg_float_to_datatype(p
->datatype
, common_data
, data
, 2);
1625 path_append_data(p
, 1, &segment
, common_data
);
1628 void path_cubic_to(struct path
*p
, float px1
, float py1
,
1629 float px2
, float py2
,
1632 VGubyte segment
= VG_CUBIC_TO_ABS
;
1633 VGubyte common_data
[sizeof(VGfloat
) * 6];
1636 data
[0] = px1
; data
[1] = py1
;
1637 data
[2] = px2
; data
[3] = py2
;
1638 data
[4] = x
; data
[5] = y
;
1640 vg_float_to_datatype(p
->datatype
, common_data
, data
, 6);
1642 path_append_data(p
, 1, &segment
, common_data
);
1645 static INLINE
void line_bounds(VGfloat
*line
/*x1,y1,x2,y2*/,
1648 bounds
[0] = MIN2(line
[0], line
[2]);
1649 bounds
[1] = MIN2(line
[1], line
[3]);
1650 bounds
[2] = MAX2(line
[0], line
[2]) - bounds
[0];
1651 bounds
[3] = MAX2(line
[1], line
[3]) - bounds
[1];
1654 static INLINE
void unite_bounds(VGfloat
*bounds
,
1657 VGfloat cx1
, cy1
, cx2
, cy2
;
1658 VGfloat nx1
, ny1
, nx2
, ny2
;
1662 cx2
= bounds
[0] + bounds
[2];
1663 cy2
= bounds
[1] + bounds
[3];
1667 nx2
= el
[0] + el
[2];
1668 ny2
= el
[1] + el
[3];
1670 bounds
[0] = MIN2(cx1
, nx1
);
1671 bounds
[1] = MIN2(cy1
, ny1
);
1672 bounds
[2] = MAX2(cx2
, nx2
) - bounds
[0];
1673 bounds
[3] = MAX2(cy2
, ny2
) - bounds
[1];
1676 static INLINE
void set_bounds(VGfloat
*bounds
,
1677 VGfloat
*element_bounds
,
1678 VGboolean
*initialized
)
1680 if (!(*initialized
)) {
1681 memcpy(bounds
, element_bounds
, 4 * sizeof(VGfloat
));
1682 *initialized
= VG_TRUE
;
1684 unite_bounds(bounds
, element_bounds
);
1687 void path_bounding_rect(struct path
*p
, float *x
, float *y
,
1692 struct path_iter_data iter
;
1695 VGfloat element_bounds
[4];
1697 VGboolean bounds_inited
= VG_FALSE
;
1699 memset(&iter
, 0, sizeof(struct path_iter_data
));
1700 memset(&bounds
, 0, sizeof(bounds
));
1702 if (!p
->num_segments
) {
1709 iter
.coords
= p
->control_points
->data
;
1711 for (i
= 0; i
< p
->num_segments
; ++i
) {
1713 iter
.segment
= ((VGubyte
*)(p
->segments
->data
))[i
];
1718 segment
= normalize_coords(&iter
, &num_coords
, coords
);
1722 case VG_MOVE_TO_ABS
:
1724 case VG_LINE_TO_ABS
: {
1725 VGfloat line
[4] = {ox
, oy
, coords
[0], coords
[1]};
1726 line_bounds(line
, element_bounds
);
1727 set_bounds(bounds
, element_bounds
, &bounds_inited
);
1730 case VG_CUBIC_TO_ABS
: {
1731 struct bezier bezier
;
1732 bezier_init(&bezier
, ox
, oy
,
1733 coords
[0], coords
[1],
1734 coords
[2], coords
[3],
1735 coords
[4], coords
[5]);
1736 bezier_exact_bounds(&bezier
, element_bounds
);
1737 set_bounds(bounds
, element_bounds
, &bounds_inited
);
1743 case VG_LCWARC_TO
: {
1745 struct matrix identity
;
1746 struct path
*path
= path_create(VG_PATH_DATATYPE_F
,
1747 1, 0, 0, 0, VG_PATH_CAPABILITY_ALL
);
1749 matrix_load_identity(&identity
);
1750 arc_init(&arc
, segment
,
1751 ox
, oy
, coords
[3], coords
[4],
1752 coords
[0], coords
[1], coords
[2]);
1754 arc_to_path(&arc
, path
, &identity
);
1756 path_bounding_rect(path
, element_bounds
+ 0, element_bounds
+ 1,
1757 element_bounds
+ 2, element_bounds
+ 3);
1758 set_bounds(bounds
, element_bounds
, &bounds_inited
);
1772 float path_length(struct path
*p
, int start_segment
, int num_segments
)
1776 struct path_iter_data iter
;
1780 VGboolean in_range
= VG_FALSE
;
1782 memset(&iter
, 0, sizeof(struct path_iter_data
));
1785 iter
.coords
= p
->control_points
->data
;
1787 for (i
= 0; i
< (start_segment
+ num_segments
); ++i
) {
1790 iter
.segment
= ((VGubyte
*)(p
->segments
->data
))[i
];
1795 segment
= normalize_coords(&iter
, &num_coords
, coords
);
1797 in_range
= (i
>= start_segment
) && i
<= (start_segment
+ num_segments
);
1802 case VG_MOVE_TO_ABS
:
1804 case VG_CLOSE_PATH
: {
1805 VGfloat line
[4] = {ox
, oy
, iter
.sx
, iter
.sy
};
1806 length
+= line_lengthv(line
);
1809 case VG_LINE_TO_ABS
: {
1810 VGfloat line
[4] = {ox
, oy
, coords
[0], coords
[1]};
1811 length
+= line_lengthv(line
);
1814 case VG_CUBIC_TO_ABS
: {
1815 struct bezier bezier
;
1816 bezier_init(&bezier
, ox
, oy
,
1817 coords
[0], coords
[1],
1818 coords
[2], coords
[3],
1819 coords
[4], coords
[5]);
1820 length
+= bezier_length(&bezier
, BEZIER_DEFAULT_ERROR
);
1826 case VG_LCWARC_TO
: {
1828 struct matrix identity
;
1829 struct path
*path
= path_create(VG_PATH_DATATYPE_F
,
1830 1, 0, 0, 0, VG_PATH_CAPABILITY_ALL
);
1832 matrix_load_identity(&identity
);
1833 arc_init(&arc
, segment
,
1834 ox
, oy
, coords
[3], coords
[4],
1835 coords
[0], coords
[1], coords
[2]);
1837 arc_to_path(&arc
, path
, &identity
);
1839 length
+= path_length(path
, 0, path_num_segments(path
));
1850 static INLINE VGboolean
point_on_current_segment(VGfloat distance
,
1852 VGfloat segment_length
)
1855 (((floatIsZero(distance
) || distance
< 0) && floatIsZero(length
)) ||
1856 ((distance
> length
|| floatsEqual(distance
, length
)) &&
1857 (floatsEqual(distance
, length
+ segment_length
) ||
1858 distance
< (length
+ segment_length
))));
1861 static VGboolean
path_point_segment(struct path_iter_data iter
,
1862 struct path_iter_data prev_iter
,
1865 VGfloat length
, VGfloat
*current_length
,
1866 VGfloat
*point
, VGfloat
*normal
)
1868 switch (iter
.segment
) {
1869 case VG_MOVE_TO_ABS
:
1871 case VG_CLOSE_PATH
: {
1872 VGfloat line
[4] = {prev_iter
.ox
, prev_iter
.oy
, iter
.sx
, iter
.sy
};
1873 VGboolean on_current_segment
= VG_FALSE
;
1874 *current_length
= line_lengthv(line
);
1875 on_current_segment
= point_on_current_segment(distance
,
1878 if (on_current_segment
) {
1879 VGfloat at
= (distance
- length
) / line_lengthv(line
);
1880 line_normal_vector(line
, normal
);
1881 line_point_at(line
, at
, point
);
1886 case VG_LINE_TO_ABS
: {
1887 VGfloat line
[4] = {prev_iter
.ox
, prev_iter
.oy
, coords
[0], coords
[1]};
1888 VGboolean on_current_segment
= VG_FALSE
;
1889 *current_length
= line_lengthv(line
);
1890 on_current_segment
= point_on_current_segment(distance
,
1893 if (on_current_segment
) {
1894 VGfloat at
= (distance
- length
) / line_lengthv(line
);
1895 line_normal_vector(line
, normal
);
1896 line_point_at(line
, at
, point
);
1901 case VG_CUBIC_TO_ABS
: {
1902 struct bezier bezier
;
1903 bezier_init(&bezier
, prev_iter
.ox
, prev_iter
.oy
,
1904 coords
[0], coords
[1],
1905 coords
[2], coords
[3],
1906 coords
[4], coords
[5]);
1907 *current_length
= bezier_length(&bezier
, BEZIER_DEFAULT_ERROR
);
1908 if (point_on_current_segment(distance
, length
, *current_length
)) {
1909 bezier_point_at_length(&bezier
, distance
- length
,
1918 case VG_LCWARC_TO
: {
1920 struct matrix identity
;
1921 struct path
*path
= path_create(VG_PATH_DATATYPE_F
,
1922 1, 0, 0, 0, VG_PATH_CAPABILITY_ALL
);
1924 matrix_load_identity(&identity
);
1925 arc_init(&arc
, iter
.segment
,
1926 prev_iter
.ox
, prev_iter
.oy
, coords
[3], coords
[4],
1927 coords
[0], coords
[1], coords
[2]);
1929 arc_to_path(&arc
, path
, &identity
);
1931 *current_length
= path_length(path
, 0, path_num_segments(path
));
1932 if (point_on_current_segment(distance
, length
, *current_length
)) {
1933 path_point(path
, 0, path_num_segments(path
),
1934 distance
- length
, point
, normal
);
1945 void path_point(struct path
*p
, VGint start_segment
, VGint num_segments
,
1946 VGfloat distance
, VGfloat
*point
, VGfloat
*normal
)
1950 struct path_iter_data iter
, prev_iter
;
1953 VGfloat current_length
= 0;
1955 memset(&iter
, 0, sizeof(struct path_iter_data
));
1956 memset(&prev_iter
, 0, sizeof(struct path_iter_data
));
1965 iter
.coords
= p
->control_points
->data
;
1969 for (i
= 0; i
< (start_segment
+ num_segments
); ++i
) {
1970 VGboolean outside_range
= (i
< start_segment
||
1971 i
>= (start_segment
+ num_segments
));
1975 iter
.segment
= ((VGubyte
*)(p
->segments
->data
))[i
];
1976 iter
.segment
= normalize_coords(&iter
, &num_coords
, coords
);
1981 if (path_point_segment(iter
, prev_iter
, coords
,
1982 distance
, length
, ¤t_length
,
1986 length
+= current_length
;
1990 *OpenVG 1.0 - 8.6.11 vgPointAlongPath
1992 * If distance is greater than or equal to the path length
1993 *(i.e., the value returned by vgPathLength when called with the same
1994 *startSegment and numSegments parameters), the visual ending point of
1998 switch (iter
.segment
) {
1999 case VG_MOVE_TO_ABS
:
2001 case VG_CLOSE_PATH
: {
2002 VGfloat line
[4] = {prev_iter
.ox
, prev_iter
.oy
, iter
.sx
, iter
.sy
};
2003 line_normal_vector(line
, normal
);
2004 line_point_at(line
, 1.f
, point
);
2007 case VG_LINE_TO_ABS
: {
2008 VGfloat line
[4] = {prev_iter
.ox
, prev_iter
.oy
, coords
[0], coords
[1]};
2009 line_normal_vector(line
, normal
);
2010 line_point_at(line
, 1.f
, point
);
2013 case VG_CUBIC_TO_ABS
: {
2014 struct bezier bezier
;
2015 bezier_init(&bezier
, prev_iter
.ox
, prev_iter
.oy
,
2016 coords
[0], coords
[1],
2017 coords
[2], coords
[3],
2018 coords
[4], coords
[5]);
2019 bezier_point_at_t(&bezier
, 1.f
, point
, normal
);
2025 case VG_LCWARC_TO
: {
2027 struct matrix identity
;
2028 struct path
*path
= path_create(VG_PATH_DATATYPE_F
,
2029 1, 0, 0, 0, VG_PATH_CAPABILITY_ALL
);
2031 matrix_load_identity(&identity
);
2032 arc_init(&arc
, iter
.segment
,
2033 prev_iter
.ox
, prev_iter
.oy
, coords
[3], coords
[4],
2034 coords
[0], coords
[1], coords
[2]);
2036 arc_to_path(&arc
, path
, &identity
);
2038 path_point(path
, 0, path_num_segments(path
),
2039 /* to make sure we're bigger than len * 2 it */
2040 2 * path_length(path
, 0, path_num_segments(path
)),
2050 VGboolean
path_is_empty(struct path
*p
)
2052 return p
->segments
->num_elements
== 0;