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
;
315 assert(polys
->num_elements
);
316 polygon_bounding_rect((((struct polygon
**)polys
->data
)[0]), bounds
);
319 max_x
= bounds
[0] + bounds
[2];
320 max_y
= bounds
[1] + bounds
[3];
321 for (i
= 1; i
< polys
->num_elements
; ++i
) {
322 struct polygon
*p
= (((struct polygon
**)polys
->data
)[i
]);
323 polygon_bounding_rect(p
, bounds
);
324 min_x
= MIN2(min_x
, bounds
[0]);
325 min_y
= MIN2(min_y
, bounds
[1]);
326 max_x
= MAX2(max_x
, bounds
[0] + bounds
[2]);
327 max_y
= MAX2(max_y
, bounds
[1] + bounds
[3]);
330 polyarray
->min_x
= min_x
;
331 polyarray
->min_y
= min_y
;
332 polyarray
->max_x
= max_x
;
333 polyarray
->max_y
= max_y
;
337 static struct polygon_array
* path_get_fill_polygons(struct path
*p
, struct matrix
*matrix
)
340 struct polygon
*current
= 0;
341 VGfloat sx
, sy
, px
, py
, ox
, oy
;
342 VGfloat x0
, y0
, x1
, y1
, x2
, y2
, x3
, y3
;
344 void *coords
= (VGfloat
*)p
->control_points
->data
;
347 if (p
->fill_polys
.polygon_array
.array
)
349 if (memcmp( &p
->fill_polys
.matrix
,
351 sizeof *matrix
) == 0 && p
->dirty
== VG_FALSE
)
353 return &p
->fill_polys
.polygon_array
;
356 array_destroy( p
->fill_polys
.polygon_array
.array
);
357 p
->fill_polys
.polygon_array
.array
= NULL
;
361 array
= array_create(sizeof(struct array
*));
363 sx
= sy
= px
= py
= ox
= oy
= 0.f
;
365 current
= polygon_create(32);
367 for (i
= 0; i
< p
->num_segments
; ++i
) {
368 VGubyte segment
= ((VGubyte
*)(p
->segments
->data
))[i
];
369 VGint command
= SEGMENT_COMMAND(segment
);
370 VGboolean relative
= SEGMENT_ABS_REL(segment
);
374 close_polygon(current
, sx
, sy
, ox
, oy
, matrix
);
379 if (current
&& polygon_vertex_count(current
) > 0) {
381 close_polygon(current
, sx
, sy
, ox
, oy
, matrix
);
382 array_append_data(array
, ¤t
, 1);
383 current
= polygon_create(32);
385 data_at(&coords
, p
, 0, 2, data
);
388 map_if_relative(ox
, oy
, relative
, &x0
, &y0
);
395 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
396 polygon_vertex_append(current
, x0
, y0
);
399 data_at(&coords
, p
, 0, 2, data
);
402 map_if_relative(ox
, oy
, relative
, &x0
, &y0
);
407 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
408 polygon_vertex_append(current
, x0
, y0
);
411 data_at(&coords
, p
, 0, 1, data
);
414 map_if_relative(ox
, oy
, relative
, &x0
, 0);
418 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
419 polygon_vertex_append(current
, x0
, y0
);
422 data_at(&coords
, p
, 0, 1, data
);
425 map_if_relative(ox
, oy
, relative
, 0, &y0
);
429 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
430 polygon_vertex_append(current
, x0
, y0
);
433 struct bezier bezier
;
434 data_at(&coords
, p
, 0, 6, data
);
443 map_if_relative(ox
, oy
, relative
, &x1
, &y1
);
444 map_if_relative(ox
, oy
, relative
, &x2
, &y2
);
445 map_if_relative(ox
, oy
, relative
, &x3
, &y3
);
450 assert(matrix_is_affine(matrix
));
451 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
452 matrix_map_point(matrix
, x1
, y1
, &x1
, &y1
);
453 matrix_map_point(matrix
, x2
, y2
, &x2
, &y2
);
454 matrix_map_point(matrix
, x3
, y3
, &x3
, &y3
);
455 bezier_init(&bezier
, x0
, y0
, x1
, y1
,
457 bezier_add_to_polygon(&bezier
, current
);
461 struct bezier bezier
;
462 data_at(&coords
, p
, 0, 4, data
);
469 map_if_relative(ox
, oy
, relative
, &x1
, &y1
);
470 map_if_relative(ox
, oy
, relative
, &x3
, &y3
);
473 { /* form a cubic out of it */
474 x2
= (x3
+ 2*x1
) / 3.f
;
475 y2
= (y3
+ 2*y1
) / 3.f
;
476 x1
= (x0
+ 2*x1
) / 3.f
;
477 y1
= (y0
+ 2*y1
) / 3.f
;
481 assert(matrix_is_affine(matrix
));
482 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
483 matrix_map_point(matrix
, x1
, y1
, &x1
, &y1
);
484 matrix_map_point(matrix
, x2
, y2
, &x2
, &y2
);
485 matrix_map_point(matrix
, x3
, y3
, &x3
, &y3
);
486 bezier_init(&bezier
, x0
, y0
, x1
, y1
,
488 bezier_add_to_polygon(&bezier
, current
);
492 struct bezier bezier
;
493 data_at(&coords
, p
, 0, 2, data
);
500 map_if_relative(ox
, oy
, relative
, &x3
, &y3
);
503 { /* form a cubic out of it */
504 x2
= (x3
+ 2*x1
) / 3.f
;
505 y2
= (y3
+ 2*y1
) / 3.f
;
506 x1
= (x0
+ 2*x1
) / 3.f
;
507 y1
= (y0
+ 2*y1
) / 3.f
;
511 assert(matrix_is_affine(matrix
));
512 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
513 matrix_map_point(matrix
, x1
, y1
, &x1
, &y1
);
514 matrix_map_point(matrix
, x2
, y2
, &x2
, &y2
);
515 matrix_map_point(matrix
, x3
, y3
, &x3
, &y3
);
516 bezier_init(&bezier
, x0
, y0
, x1
, y1
,
518 bezier_add_to_polygon(&bezier
, current
);
522 struct bezier bezier
;
523 data_at(&coords
, p
, 0, 4, data
);
532 map_if_relative(ox
, oy
, relative
, &x2
, &y2
);
533 map_if_relative(ox
, oy
, relative
, &x3
, &y3
);
538 assert(matrix_is_affine(matrix
));
539 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
540 matrix_map_point(matrix
, x1
, y1
, &x1
, &y1
);
541 matrix_map_point(matrix
, x2
, y2
, &x2
, &y2
);
542 matrix_map_point(matrix
, x3
, y3
, &x3
, &y3
);
543 bezier_init(&bezier
, x0
, y0
, x1
, y1
,
545 bezier_add_to_polygon(&bezier
, current
);
555 data_at(&coords
, p
, 0, 5, data
);
563 map_if_relative(ox
, oy
, relative
, &x1
, &y1
);
565 debug_printf("------- ARC (%f, %f), (%f, %f) %f, %f, %f\n",
566 x0
, y0
, x1
, y1
, rh
, rv
, rot
);
568 arc_init(&arc
, command
, x0
, y0
, x1
, y1
,
570 arc_add_to_polygon(&arc
, current
,
580 assert(!"Unknown segment!");
584 if (polygon_vertex_count(current
) > 0) {
585 close_polygon(current
, sx
, sy
, ox
, oy
, matrix
);
586 array_append_data(array
, ¤t
, 1);
588 polygon_destroy(current
);
591 p
->fill_polys
.polygon_array
.array
= array
;
592 p
->fill_polys
.matrix
= *matrix
;
594 polygon_array_calculate_bounds( &p
->fill_polys
.polygon_array
);
598 return &p
->fill_polys
.polygon_array
;
601 VGbyte
path_datatype_size(struct path
*p
)
603 return size_for_datatype(p
->datatype
);
606 VGPathDatatype
path_datatype(struct path
*p
)
611 VGfloat
path_scale(struct path
*p
)
616 VGfloat
path_bias(struct path
*p
)
621 VGint
path_num_coords(struct path
*p
)
623 return num_elements_for_segments((VGubyte
*)p
->segments
->data
,
627 void path_modify_coords(struct path
*p
,
630 const void * pathData
)
632 VGubyte
*segments
= (VGubyte
*)(p
->segments
->data
);
633 VGint count
= num_elements_for_segments(&segments
[startIndex
], numSegments
);
634 VGint start_cp
= num_elements_for_segments(segments
, startIndex
);
636 array_change_data(p
->control_points
, pathData
, start_cp
, count
);
637 coords_adjust_by_scale_bias(p
,
638 ((VGubyte
*)p
->control_points
->data
) +
639 (startIndex
* p
->control_points
->datatype_size
),
641 p
->scale
, p
->bias
, p
->datatype
);
643 p
->dirty_stroke
= VG_TRUE
;
646 void path_for_each_segment(struct path
*path
,
651 struct path_for_each_data p
;
653 void *coords
= (VGfloat
*)path
->control_points
->data
;
656 p
.sx
= p
.sy
= p
.px
= p
.py
= p
.ox
= p
.oy
= 0.f
;
657 p
.user_data
= user_data
;
659 for (i
= 0; i
< path
->num_segments
; ++i
) {
663 p
.segment
= ((VGubyte
*)(path
->segments
->data
))[i
];
664 command
= SEGMENT_COMMAND(p
.segment
);
665 relative
= SEGMENT_ABS_REL(p
.segment
);
672 data_at(&coords
, path
, 0, 2, data
);
673 map_if_relative(p
.ox
, p
.oy
, relative
, &data
[0], &data
[1]);
683 data_at(&coords
, path
, 0, 2, data
);
684 map_if_relative(p
.ox
, p
.oy
, relative
, &data
[0], &data
[1]);
692 data_at(&coords
, path
, 0, 1, data
);
693 map_if_relative(p
.ox
, p
.oy
, relative
, &data
[0], 0);
694 p
.segment
= VG_LINE_TO
;
703 data_at(&coords
, path
, 0, 1, data
);
704 map_if_relative(p
.ox
, p
.oy
, relative
, 0, &data
[0]);
705 p
.segment
= VG_LINE_TO
;
715 data_at(&coords
, path
, 0, 6, data
);
716 map_if_relative(p
.ox
, p
.oy
, relative
, &data
[0], &data
[1]);
717 map_if_relative(p
.ox
, p
.oy
, relative
, &data
[2], &data
[3]);
718 map_if_relative(p
.ox
, p
.oy
, relative
, &data
[4], &data
[5]);
727 data_at(&coords
, path
, 0, 4, data
);
728 map_if_relative(p
.ox
, p
.oy
, relative
, &data
[0], &data
[1]);
729 map_if_relative(p
.ox
, p
.oy
, relative
, &data
[2], &data
[3]);
738 data_at(&coords
, path
, 0, 2, data
);
739 map_if_relative(p
.ox
, p
.oy
, relative
, &data
[0], &data
[1]);
748 data_at(&coords
, path
, 0, 4, data
);
749 map_if_relative(p
.ox
, p
.oy
, relative
, &data
[0], &data
[1]);
750 map_if_relative(p
.ox
, p
.oy
, relative
, &data
[2], &data
[3]);
762 data_at(&coords
, path
, 0, 5, data
);
763 map_if_relative(p
.ox
, p
.oy
, relative
, &data
[3], &data
[4]);
765 debug_printf("------- ARC (%f, %f), (%f, %f) %f, %f, %f\n",
766 p
.ox
, p
.oy
, data
[3], data
[4], data
[0], data
[1], data
[2]);
777 assert(!"Unknown segment!");
782 struct transform_data
{
783 struct array
*segments
;
784 struct array
*coords
;
786 struct matrix
*matrix
;
788 VGPathDatatype datatype
;
791 static VGboolean
transform_cb(struct path
*p
,
792 struct path_for_each_data
*pd
)
794 struct transform_data
*td
= (struct transform_data
*)pd
->user_data
;
795 VGint num_coords
= num_elements_for_segments(&pd
->segment
, 1);
796 VGubyte segment
= SEGMENT_COMMAND(pd
->segment
);/* abs bit is 0 */
798 VGubyte common_data
[sizeof(VGfloat
)*8];
800 memcpy(data
, pd
->coords
, sizeof(VGfloat
) * num_coords
);
806 matrix_map_point(td
->matrix
,
807 data
[0], data
[1], &data
[0], &data
[1]);
810 matrix_map_point(td
->matrix
,
811 data
[0], data
[1], &data
[0], &data
[1]);
818 matrix_map_point(td
->matrix
,
819 data
[0], data
[1], &data
[0], &data
[1]);
820 matrix_map_point(td
->matrix
,
821 data
[2], data
[3], &data
[2], &data
[3]);
824 matrix_map_point(td
->matrix
,
825 data
[0], data
[1], &data
[0], &data
[1]);
826 matrix_map_point(td
->matrix
,
827 data
[2], data
[3], &data
[2], &data
[3]);
828 matrix_map_point(td
->matrix
,
829 data
[4], data
[5], &data
[4], &data
[5]);
832 matrix_map_point(td
->matrix
,
833 data
[0], data
[1], &data
[0], &data
[1]);
836 matrix_map_point(td
->matrix
,
837 data
[0], data
[1], &data
[0], &data
[1]);
838 matrix_map_point(td
->matrix
,
839 data
[2], data
[3], &data
[2], &data
[3]);
846 struct path
*path
= path_create(td
->datatype
,
847 1, 0, 0, 0, VG_PATH_CAPABILITY_ALL
);
848 arc_init(&arc
, segment
,
849 pd
->ox
, pd
->oy
, data
[3], data
[4],
850 data
[0], data
[1], data
[2]);
852 arc_to_path(&arc
, path
, td
->matrix
);
854 num_coords
= path_num_coords(path
);
856 array_append_data(td
->segments
, path
->segments
->data
,
858 array_append_data(td
->coords
, path
->control_points
->data
,
869 vg_float_to_datatype(td
->datatype
, common_data
, data
, num_coords
);
871 array_append_data(td
->segments
, &pd
->segment
, 1);
872 array_append_data(td
->coords
, common_data
, num_coords
);
876 void path_transform(struct path
*dst
, struct path
*src
)
878 struct transform_data data
;
879 struct vg_context
*ctx
= dst
->base
.ctx
;
881 data
.segments
= dst
->segments
;
882 data
.coords
= dst
->control_points
;
883 data
.matrix
= &ctx
->state
.vg
.path_user_to_surface_matrix
;
884 data
.datatype
= dst
->datatype
;
886 path_for_each_segment(src
, transform_cb
, (void*)&data
);
888 dst
->num_segments
= dst
->segments
->num_elements
;
889 dst
->dirty
= VG_TRUE
;
890 dst
->dirty_stroke
= VG_TRUE
;
893 void path_append_path(struct path
*dst
,
896 VGint num_coords
= path_num_coords(src
);
897 void *dst_data
= malloc(size_for_datatype(dst
->datatype
) * num_coords
);
898 array_append_data(dst
->segments
,
901 convert_path(src
, dst
->datatype
,
902 dst_data
, num_coords
);
903 array_append_data(dst
->control_points
,
908 dst
->num_segments
+= src
->num_segments
;
909 dst
->dirty
= VG_TRUE
;
910 dst
->dirty_stroke
= VG_TRUE
;
913 static INLINE VGboolean
is_segment_arc(VGubyte segment
)
915 VGubyte scommand
= SEGMENT_COMMAND(segment
);
916 return (scommand
== VG_SCCWARC_TO
||
917 scommand
== VG_SCWARC_TO
||
918 scommand
== VG_LCCWARC_TO
||
919 scommand
== VG_LCWARC_TO
);
922 struct path_iter_data
{
926 VGfloat px
, py
, ox
, oy
, sx
, sy
;
928 static INLINE VGubyte
normalize_coords(struct path_iter_data
*pd
,
932 VGint command
= SEGMENT_COMMAND(pd
->segment
);
933 VGboolean relative
= SEGMENT_ABS_REL(pd
->segment
);
940 return VG_CLOSE_PATH
;
943 data_at(&pd
->coords
, pd
->path
, 0, 2, data
);
944 map_if_relative(pd
->ox
, pd
->oy
, relative
, &data
[0], &data
[1]);
952 return VG_MOVE_TO_ABS
;
955 data_at(&pd
->coords
, pd
->path
, 0, 2, data
);
956 map_if_relative(pd
->ox
, pd
->oy
, relative
, &data
[0], &data
[1]);
962 return VG_LINE_TO_ABS
;
965 data_at(&pd
->coords
, pd
->path
, 0, 1, data
);
966 map_if_relative(pd
->ox
, pd
->oy
, relative
, &data
[0], 0);
973 return VG_LINE_TO_ABS
;
976 data_at(&pd
->coords
, pd
->path
, 0, 1, data
);
977 map_if_relative(pd
->ox
, pd
->oy
, relative
, 0, &data
[0]);
985 return VG_LINE_TO_ABS
;
988 data_at(&pd
->coords
, pd
->path
, 0, 6, data
);
989 map_if_relative(pd
->ox
, pd
->oy
, relative
, &data
[0], &data
[1]);
990 map_if_relative(pd
->ox
, pd
->oy
, relative
, &data
[2], &data
[3]);
991 map_if_relative(pd
->ox
, pd
->oy
, relative
, &data
[4], &data
[5]);
997 return VG_CUBIC_TO_ABS
;
1001 VGfloat x0
, y0
, x1
, y1
, x2
, y2
, x3
, y3
;
1002 data_at(&pd
->coords
, pd
->path
, 0, 4, data
);
1009 map_if_relative(pd
->ox
, pd
->oy
, relative
, &x1
, &y1
);
1010 map_if_relative(pd
->ox
, pd
->oy
, relative
, &x3
, &y3
);
1013 { /* form a cubic out of it */
1014 x2
= (x3
+ 2*x1
) / 3.f
;
1015 y2
= (y3
+ 2*y1
) / 3.f
;
1016 x1
= (x0
+ 2*x1
) / 3.f
;
1017 y1
= (y0
+ 2*y1
) / 3.f
;
1028 return VG_CUBIC_TO_ABS
;
1032 VGfloat x0
, y0
, x1
, y1
, x2
, y2
, x3
, y3
;
1033 data_at(&pd
->coords
, pd
->path
, 0, 2, data
);
1036 x1
= 2 * pd
->ox
- pd
->px
;
1037 y1
= 2 * pd
->oy
- pd
->py
;
1040 map_if_relative(pd
->ox
, pd
->oy
, relative
, &x3
, &y3
);
1043 { /* form a cubic out of it */
1044 x2
= (x3
+ 2*x1
) / 3.f
;
1045 y2
= (y3
+ 2*y1
) / 3.f
;
1046 x1
= (x0
+ 2*x1
) / 3.f
;
1047 y1
= (y0
+ 2*y1
) / 3.f
;
1058 return VG_CUBIC_TO_ABS
;
1061 case VG_SCUBIC_TO
: {
1062 VGfloat x0
, y0
, x1
, y1
, x2
, y2
, x3
, y3
;
1063 data_at(&pd
->coords
, pd
->path
, 0, 4, data
);
1066 x1
= 2*pd
->ox
-pd
->px
;
1067 y1
= 2*pd
->oy
-pd
->py
;
1072 map_if_relative(pd
->ox
, pd
->oy
, relative
, &x2
, &y2
);
1073 map_if_relative(pd
->ox
, pd
->oy
, relative
, &x3
, &y3
);
1085 return VG_CUBIC_TO_ABS
;
1091 case VG_LCWARC_TO
: {
1092 data_at(&pd
->coords
, pd
->path
, 0, 5, data
);
1093 map_if_relative(pd
->ox
, pd
->oy
, relative
, &data
[3], &data
[4]);
1099 return command
| VG_ABSOLUTE
;
1104 assert(!"Unknown segment!");
1108 static void linearly_interpolate(VGfloat
*result
,
1109 const VGfloat
*start
,
1115 for (i
= 0; i
< number
; ++i
) {
1116 result
[i
] = start
[i
] + (end
[i
] - start
[i
]) * amount
;
1120 VGboolean
path_interpolate(struct path
*dst
,
1121 struct path
*start
, struct path
*end
,
1124 /* temporary path that we can discard if it will turn
1125 * out that start is not compatible with end */
1126 struct path
*res_path
= path_create(dst
->datatype
,
1130 VGfloat start_coords
[8];
1131 VGfloat end_coords
[8];
1133 VGubyte common_data
[sizeof(VGfloat
)*8];
1134 struct path_iter_data start_iter
, end_iter
;
1136 memset(&start_iter
, 0, sizeof(struct path_iter_data
));
1137 memset(&end_iter
, 0, sizeof(struct path_iter_data
));
1139 start_iter
.path
= start
;
1140 start_iter
.coords
= start
->control_points
->data
;
1141 end_iter
.path
= end
;
1142 end_iter
.coords
= end
->control_points
->data
;
1144 for (i
= 0; i
< start
->num_segments
; ++i
) {
1146 VGubyte ssegment
, esegment
;
1147 VGint snum_coords
, enum_coords
;
1148 start_iter
.segment
= ((VGubyte
*)(start
->segments
->data
))[i
];
1149 end_iter
.segment
= ((VGubyte
*)(end
->segments
->data
))[i
];
1151 ssegment
= normalize_coords(&start_iter
, &snum_coords
,
1153 esegment
= normalize_coords(&end_iter
, &enum_coords
,
1156 if (is_segment_arc(ssegment
)) {
1157 if (!is_segment_arc(esegment
)) {
1158 path_destroy(res_path
);
1165 } else if (is_segment_arc(esegment
)) {
1166 path_destroy(res_path
);
1169 else if (ssegment
!= esegment
) {
1170 path_destroy(res_path
);
1176 linearly_interpolate(results
, start_coords
, end_coords
,
1177 amount
, snum_coords
);
1178 vg_float_to_datatype(dst
->datatype
, common_data
, results
, snum_coords
);
1179 path_append_data(res_path
, 1, &segment
, common_data
);
1182 path_append_path(dst
, res_path
);
1183 path_destroy(res_path
);
1185 dst
->dirty
= VG_TRUE
;
1186 dst
->dirty_stroke
= VG_TRUE
;
1191 void path_clear(struct path
*p
, VGbitfield capabilities
)
1193 path_set_capabilities(p
, capabilities
);
1194 array_destroy(p
->segments
);
1195 array_destroy(p
->control_points
);
1196 p
->segments
= array_create(size_for_datatype(VG_PATH_DATATYPE_S_8
));
1197 p
->control_points
= array_create(size_for_datatype(p
->datatype
));
1198 p
->num_segments
= 0;
1200 p
->dirty_stroke
= VG_TRUE
;
1203 struct path
* path_create_stroke(struct path
*p
,
1204 struct matrix
*matrix
)
1207 VGfloat sx
, sy
, px
, py
, ox
, oy
;
1208 VGfloat x0
, y0
, x1
, y1
, x2
, y2
, x3
, y3
;
1210 void *coords
= (VGfloat
*)p
->control_points
->data
;
1211 int dashed
= (p
->base
.ctx
->state
.vg
.stroke
.dash_pattern_num
? 1 : 0);
1212 struct dash_stroker stroker
;
1213 struct vg_state
*vg_state
= &p
->base
.ctx
->state
.vg
;
1215 if (p
->stroked
.path
)
1217 /* ### compare the dash patterns to see if we can cache them.
1218 * for now we simply always bail out if the path is dashed.
1220 if (memcmp( &p
->stroked
.matrix
,
1222 sizeof *matrix
) == 0 &&
1223 !dashed
&& !p
->dirty_stroke
&&
1224 floatsEqual(p
->stroked
.stroke_width
, vg_state
->stroke
.line_width
.f
) &&
1225 floatsEqual(p
->stroked
.miter_limit
, vg_state
->stroke
.miter_limit
.f
) &&
1226 p
->stroked
.cap_style
== vg_state
->stroke
.cap_style
&&
1227 p
->stroked
.join_style
== vg_state
->stroke
.join_style
)
1229 return p
->stroked
.path
;
1232 path_destroy( p
->stroked
.path
);
1233 p
->stroked
.path
= NULL
;
1238 sx
= sy
= px
= py
= ox
= oy
= 0.f
;
1241 dash_stroker_init((struct stroker
*)&stroker
, vg_state
);
1243 stroker_init((struct stroker
*)&stroker
, vg_state
);
1245 stroker_begin((struct stroker
*)&stroker
);
1247 for (i
= 0; i
< p
->num_segments
; ++i
) {
1248 VGubyte segment
= ((VGubyte
*)(p
->segments
->data
))[i
];
1249 VGint command
= SEGMENT_COMMAND(segment
);
1250 VGboolean relative
= SEGMENT_ABS_REL(segment
);
1253 case VG_CLOSE_PATH
: {
1256 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
1257 stroker_line_to((struct stroker
*)&stroker
, x0
, y0
);
1261 data_at(&coords
, p
, 0, 2, data
);
1264 map_if_relative(ox
, oy
, relative
, &x0
, &y0
);
1271 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
1272 stroker_move_to((struct stroker
*)&stroker
, x0
, y0
);
1275 data_at(&coords
, p
, 0, 2, data
);
1278 map_if_relative(ox
, oy
, relative
, &x0
, &y0
);
1283 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
1284 stroker_line_to((struct stroker
*)&stroker
, x0
, y0
);
1287 data_at(&coords
, p
, 0, 1, data
);
1290 map_if_relative(ox
, oy
, relative
, &x0
, 0);
1294 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
1295 stroker_line_to((struct stroker
*)&stroker
, x0
, y0
);
1298 data_at(&coords
, p
, 0, 1, data
);
1301 map_if_relative(ox
, oy
, relative
, 0, &y0
);
1305 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
1306 stroker_line_to((struct stroker
*)&stroker
, x0
, y0
);
1309 data_at(&coords
, p
, 0, 6, data
);
1318 map_if_relative(ox
, oy
, relative
, &x1
, &y1
);
1319 map_if_relative(ox
, oy
, relative
, &x2
, &y2
);
1320 map_if_relative(ox
, oy
, relative
, &x3
, &y3
);
1321 if (floatsEqual(x1
, ox
) && floatsEqual(y1
, oy
) &&
1322 floatsEqual(x1
, x2
) && floatsEqual(y1
, y2
) &&
1323 floatsEqual(x2
, x3
) && floatsEqual(y2
, y3
)) {
1324 /*ignore the empty segment */
1326 } else if (floatsEqual(x3
, ox
) && floatsEqual(y3
, oy
)) {
1327 /* if dup vertex, emit a line */
1330 matrix_map_point(matrix
, x3
, y3
, &x3
, &y3
);
1331 stroker_line_to((struct stroker
*)&stroker
, x3
, y3
);
1338 assert(matrix_is_affine(matrix
));
1339 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
1340 matrix_map_point(matrix
, x1
, y1
, &x1
, &y1
);
1341 matrix_map_point(matrix
, x2
, y2
, &x2
, &y2
);
1342 matrix_map_point(matrix
, x3
, y3
, &x3
, &y3
);
1343 stroker_curve_to((struct stroker
*)&stroker
, x1
, y1
, x2
, y2
, x3
, y3
);
1347 data_at(&coords
, p
, 0, 4, data
);
1354 map_if_relative(ox
, oy
, relative
, &x1
, &y1
);
1355 map_if_relative(ox
, oy
, relative
, &x3
, &y3
);
1358 { /* form a cubic out of it */
1359 x2
= (x3
+ 2*x1
) / 3.f
;
1360 y2
= (y3
+ 2*y1
) / 3.f
;
1361 x1
= (x0
+ 2*x1
) / 3.f
;
1362 y1
= (y0
+ 2*y1
) / 3.f
;
1364 if (floatsEqual(x1
, ox
) && floatsEqual(y1
, oy
) &&
1365 floatsEqual(x1
, x2
) && floatsEqual(y1
, y2
) &&
1366 floatsEqual(x2
, x3
) && floatsEqual(y2
, y3
)) {
1367 /*ignore the empty segment */
1369 } else if (floatsEqual(x3
, ox
) && floatsEqual(y3
, oy
)) {
1370 /* if dup vertex, emit a line */
1373 matrix_map_point(matrix
, x3
, y3
, &x3
, &y3
);
1374 stroker_line_to((struct stroker
*)&stroker
, x3
, y3
);
1379 assert(matrix_is_affine(matrix
));
1380 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
1381 matrix_map_point(matrix
, x1
, y1
, &x1
, &y1
);
1382 matrix_map_point(matrix
, x2
, y2
, &x2
, &y2
);
1383 matrix_map_point(matrix
, x3
, y3
, &x3
, &y3
);
1384 stroker_curve_to((struct stroker
*)&stroker
, x1
, y1
, x2
, y2
, x3
, y3
);
1388 data_at(&coords
, p
, 0, 2, data
);
1395 map_if_relative(ox
, oy
, relative
, &x3
, &y3
);
1398 { /* form a cubic out of it */
1399 x2
= (x3
+ 2*x1
) / 3.f
;
1400 y2
= (y3
+ 2*y1
) / 3.f
;
1401 x1
= (x0
+ 2*x1
) / 3.f
;
1402 y1
= (y0
+ 2*y1
) / 3.f
;
1404 if (floatsEqual(x1
, ox
) && floatsEqual(y1
, oy
) &&
1405 floatsEqual(x1
, x2
) && floatsEqual(y1
, y2
) &&
1406 floatsEqual(x2
, x3
) && floatsEqual(y2
, y3
)) {
1407 /*ignore the empty segment */
1409 } else if (floatsEqual(x3
, ox
) && floatsEqual(y3
, oy
)) {
1410 /* if dup vertex, emit a line */
1413 matrix_map_point(matrix
, x3
, y3
, &x3
, &y3
);
1414 stroker_line_to((struct stroker
*)&stroker
, x3
, y3
);
1419 assert(matrix_is_affine(matrix
));
1420 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
1421 matrix_map_point(matrix
, x1
, y1
, &x1
, &y1
);
1422 matrix_map_point(matrix
, x2
, y2
, &x2
, &y2
);
1423 matrix_map_point(matrix
, x3
, y3
, &x3
, &y3
);
1424 stroker_curve_to((struct stroker
*)&stroker
, x1
, y1
, x2
, y2
, x3
, y3
);
1427 case VG_SCUBIC_TO
: {
1428 data_at(&coords
, p
, 0, 4, data
);
1437 map_if_relative(ox
, oy
, relative
, &x2
, &y2
);
1438 map_if_relative(ox
, oy
, relative
, &x3
, &y3
);
1439 if (floatsEqual(x1
, ox
) && floatsEqual(y1
, oy
) &&
1440 floatsEqual(x1
, x2
) && floatsEqual(y1
, y2
) &&
1441 floatsEqual(x2
, x3
) && floatsEqual(y2
, y3
)) {
1442 /*ignore the empty segment */
1444 } else if (floatsEqual(x3
, ox
) && floatsEqual(y3
, oy
)) {
1445 /* if dup vertex, emit a line */
1448 matrix_map_point(matrix
, x3
, y3
, &x3
, &y3
);
1449 stroker_line_to((struct stroker
*)&stroker
, x3
, y3
);
1456 assert(matrix_is_affine(matrix
));
1457 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
1458 matrix_map_point(matrix
, x1
, y1
, &x1
, &y1
);
1459 matrix_map_point(matrix
, x2
, y2
, &x2
, &y2
);
1460 matrix_map_point(matrix
, x3
, y3
, &x3
, &y3
);
1461 stroker_curve_to((struct stroker
*)&stroker
, x1
, y1
, x2
, y2
, x3
, y3
);
1467 case VG_LCWARC_TO
: {
1468 VGfloat rh
, rv
, rot
;
1471 data_at(&coords
, p
, 0, 5, data
);
1479 map_if_relative(ox
, oy
, relative
, &x1
, &y1
);
1480 if (floatsEqual(x1
, ox
) && floatsEqual(y1
, oy
)) {
1481 /* if dup vertex, emit a line */
1484 matrix_map_point(matrix
, x1
, y1
, &x1
, &y1
);
1485 stroker_line_to((struct stroker
*)&stroker
, x1
, y1
);
1488 arc_init(&arc
, command
, x0
, y0
, x1
, y1
,
1490 arc_stroke_cb(&arc
, (struct stroker
*)&stroker
,
1500 assert(!"Unknown segment!");
1504 stroker_end((struct stroker
*)&stroker
);
1507 dash_stroker_cleanup((struct dash_stroker
*)&stroker
);
1509 stroker_cleanup((struct stroker
*)&stroker
);
1511 p
->stroked
.path
= stroker
.base
.path
;
1512 p
->stroked
.matrix
= *matrix
;
1513 p
->dirty_stroke
= VG_FALSE
;
1514 p
->stroked
.stroke_width
= vg_state
->stroke
.line_width
.f
;
1515 p
->stroked
.miter_limit
= vg_state
->stroke
.miter_limit
.f
;
1516 p
->stroked
.cap_style
= vg_state
->stroke
.cap_style
;
1517 p
->stroked
.join_style
= vg_state
->stroke
.join_style
;
1519 return stroker
.base
.path
;
1522 void path_render(struct path
*p
, VGbitfield paintModes
)
1524 struct vg_context
*ctx
= vg_current_context();
1525 struct matrix
*mat
= &ctx
->state
.vg
.path_user_to_surface_matrix
;
1527 vg_validate_state(ctx
);
1529 shader_set_drawing_image(ctx
->shader
, VG_FALSE
);
1530 shader_set_image(ctx
->shader
, 0);
1532 fprintf(stderr
, "Matrix(11=%f 12=%f 13=%f 21=%f 22=%f 23=%f 31=%f 32=%f 33=%f)\n",
1533 mat
->m
[0], mat
->m
[1], mat
->m
[2],
1534 mat
->m
[3], mat
->m
[4], mat
->m
[5],
1535 mat
->m
[6], mat
->m
[7], mat
->m
[8]);
1537 if (paintModes
& VG_FILL_PATH
) {
1538 /* First the fill */
1539 shader_set_paint(ctx
->shader
, ctx
->state
.vg
.fill_paint
);
1540 shader_bind(ctx
->shader
);
1544 if (paintModes
& VG_STROKE_PATH
){
1545 /* 8.7.5: "line width less than or equal to 0 prevents stroking from
1547 if (ctx
->state
.vg
.stroke
.line_width
.f
<= 0)
1549 shader_set_paint(ctx
->shader
, ctx
->state
.vg
.stroke_paint
);
1550 shader_bind(ctx
->shader
);
1555 void path_fill(struct path
*p
, struct matrix
*mat
)
1557 struct vg_context
*ctx
= vg_current_context();
1559 struct polygon_array
*polygon_array
= path_get_fill_polygons(p
, mat
);
1560 struct array
*polys
= polygon_array
->array
;
1562 if (!polygon_array
|| !polys
|| !polys
->num_elements
) {
1565 polygon_array_fill(polygon_array
, ctx
);
1569 void path_stroke(struct path
*p
)
1571 struct vg_context
*ctx
= vg_current_context();
1572 struct matrix
*mat
= &ctx
->state
.vg
.path_user_to_surface_matrix
;
1573 VGFillRule old_fill
= ctx
->state
.vg
.fill_rule
;
1574 struct matrix identity
;
1575 struct path
*stroke
;
1577 matrix_load_identity(&identity
);
1578 stroke
= path_create_stroke(p
, &identity
);
1579 if (stroke
&& !path_is_empty(stroke
)) {
1580 ctx
->state
.vg
.fill_rule
= VG_NON_ZERO
;
1582 path_fill(stroke
, mat
);
1584 ctx
->state
.vg
.fill_rule
= old_fill
;
1588 void path_move_to(struct path
*p
, float x
, float y
)
1590 VGubyte segment
= VG_MOVE_TO_ABS
;
1591 VGubyte common_data
[sizeof(VGfloat
) * 2];
1592 VGfloat data
[2] = {x
, y
};
1594 vg_float_to_datatype(p
->datatype
, common_data
, data
, 2);
1595 path_append_data(p
, 1, &segment
, common_data
);
1598 void path_line_to(struct path
*p
, float x
, float y
)
1600 VGubyte segment
= VG_LINE_TO_ABS
;
1601 VGubyte common_data
[sizeof(VGfloat
) * 2];
1602 VGfloat data
[2] = {x
, y
};
1604 vg_float_to_datatype(p
->datatype
, common_data
, data
, 2);
1606 path_append_data(p
, 1, &segment
, common_data
);
1609 void path_cubic_to(struct path
*p
, float px1
, float py1
,
1610 float px2
, float py2
,
1613 VGubyte segment
= VG_CUBIC_TO_ABS
;
1614 VGubyte common_data
[sizeof(VGfloat
) * 6];
1617 data
[0] = px1
; data
[1] = py1
;
1618 data
[2] = px2
; data
[3] = py2
;
1619 data
[4] = x
; data
[5] = y
;
1621 vg_float_to_datatype(p
->datatype
, common_data
, data
, 6);
1623 path_append_data(p
, 1, &segment
, common_data
);
1626 static INLINE
void line_bounds(VGfloat
*line
/*x1,y1,x2,y2*/,
1629 bounds
[0] = MIN2(line
[0], line
[2]);
1630 bounds
[1] = MIN2(line
[1], line
[3]);
1631 bounds
[2] = MAX2(line
[0], line
[2]) - bounds
[0];
1632 bounds
[3] = MAX2(line
[1], line
[3]) - bounds
[1];
1635 static INLINE
void unite_bounds(VGfloat
*bounds
,
1638 VGfloat cx1
, cy1
, cx2
, cy2
;
1639 VGfloat nx1
, ny1
, nx2
, ny2
;
1643 cx2
= bounds
[0] + bounds
[2];
1644 cy2
= bounds
[1] + bounds
[3];
1648 nx2
= el
[0] + el
[2];
1649 ny2
= el
[1] + el
[3];
1651 bounds
[0] = MIN2(cx1
, nx1
);
1652 bounds
[1] = MIN2(cy1
, ny1
);
1653 bounds
[2] = MAX2(cx2
, nx2
) - bounds
[0];
1654 bounds
[3] = MAX2(cy2
, ny2
) - bounds
[1];
1657 static INLINE
void set_bounds(VGfloat
*bounds
,
1658 VGfloat
*element_bounds
,
1659 VGboolean
*initialized
)
1661 if (!(*initialized
)) {
1662 memcpy(bounds
, element_bounds
, 4 * sizeof(VGfloat
));
1663 *initialized
= VG_TRUE
;
1665 unite_bounds(bounds
, element_bounds
);
1668 void path_bounding_rect(struct path
*p
, float *x
, float *y
,
1673 struct path_iter_data iter
;
1676 VGfloat element_bounds
[4];
1678 VGboolean bounds_inited
= VG_FALSE
;
1680 memset(&iter
, 0, sizeof(struct path_iter_data
));
1681 memset(&bounds
, 0, sizeof(bounds
));
1683 if (!p
->num_segments
) {
1690 iter
.coords
= p
->control_points
->data
;
1692 for (i
= 0; i
< p
->num_segments
; ++i
) {
1694 iter
.segment
= ((VGubyte
*)(p
->segments
->data
))[i
];
1699 segment
= normalize_coords(&iter
, &num_coords
, coords
);
1703 case VG_MOVE_TO_ABS
:
1705 case VG_LINE_TO_ABS
: {
1706 VGfloat line
[4] = {ox
, oy
, coords
[0], coords
[1]};
1707 line_bounds(line
, element_bounds
);
1708 set_bounds(bounds
, element_bounds
, &bounds_inited
);
1711 case VG_CUBIC_TO_ABS
: {
1712 struct bezier bezier
;
1713 bezier_init(&bezier
, ox
, oy
,
1714 coords
[0], coords
[1],
1715 coords
[2], coords
[3],
1716 coords
[4], coords
[5]);
1717 bezier_exact_bounds(&bezier
, element_bounds
);
1718 set_bounds(bounds
, element_bounds
, &bounds_inited
);
1724 case VG_LCWARC_TO
: {
1726 struct matrix identity
;
1727 struct path
*path
= path_create(VG_PATH_DATATYPE_F
,
1728 1, 0, 0, 0, VG_PATH_CAPABILITY_ALL
);
1730 matrix_load_identity(&identity
);
1731 arc_init(&arc
, segment
,
1732 ox
, oy
, coords
[3], coords
[4],
1733 coords
[0], coords
[1], coords
[2]);
1735 arc_to_path(&arc
, path
, &identity
);
1737 path_bounding_rect(path
, element_bounds
+ 0, element_bounds
+ 1,
1738 element_bounds
+ 2, element_bounds
+ 3);
1739 set_bounds(bounds
, element_bounds
, &bounds_inited
);
1753 float path_length(struct path
*p
, int start_segment
, int num_segments
)
1757 struct path_iter_data iter
;
1761 VGboolean in_range
= VG_FALSE
;
1763 memset(&iter
, 0, sizeof(struct path_iter_data
));
1766 iter
.coords
= p
->control_points
->data
;
1768 for (i
= 0; i
< (start_segment
+ num_segments
); ++i
) {
1771 iter
.segment
= ((VGubyte
*)(p
->segments
->data
))[i
];
1776 segment
= normalize_coords(&iter
, &num_coords
, coords
);
1778 in_range
= (i
>= start_segment
) && i
<= (start_segment
+ num_segments
);
1783 case VG_MOVE_TO_ABS
:
1785 case VG_CLOSE_PATH
: {
1786 VGfloat line
[4] = {ox
, oy
, iter
.sx
, iter
.sy
};
1787 length
+= line_lengthv(line
);
1790 case VG_LINE_TO_ABS
: {
1791 VGfloat line
[4] = {ox
, oy
, coords
[0], coords
[1]};
1792 length
+= line_lengthv(line
);
1795 case VG_CUBIC_TO_ABS
: {
1796 struct bezier bezier
;
1797 bezier_init(&bezier
, ox
, oy
,
1798 coords
[0], coords
[1],
1799 coords
[2], coords
[3],
1800 coords
[4], coords
[5]);
1801 length
+= bezier_length(&bezier
, BEZIER_DEFAULT_ERROR
);
1807 case VG_LCWARC_TO
: {
1809 struct matrix identity
;
1810 struct path
*path
= path_create(VG_PATH_DATATYPE_F
,
1811 1, 0, 0, 0, VG_PATH_CAPABILITY_ALL
);
1813 matrix_load_identity(&identity
);
1814 arc_init(&arc
, segment
,
1815 ox
, oy
, coords
[3], coords
[4],
1816 coords
[0], coords
[1], coords
[2]);
1818 arc_to_path(&arc
, path
, &identity
);
1820 length
+= path_length(path
, 0, path_num_segments(path
));
1831 static INLINE VGboolean
point_on_current_segment(VGfloat distance
,
1833 VGfloat segment_length
)
1836 (((floatIsZero(distance
) || distance
< 0) && floatIsZero(length
)) ||
1837 ((distance
> length
|| floatsEqual(distance
, length
)) &&
1838 (floatsEqual(distance
, length
+ segment_length
) ||
1839 distance
< (length
+ segment_length
))));
1842 static VGboolean
path_point_segment(struct path_iter_data iter
,
1843 struct path_iter_data prev_iter
,
1846 VGfloat length
, VGfloat
*current_length
,
1847 VGfloat
*point
, VGfloat
*normal
)
1849 switch (iter
.segment
) {
1850 case VG_MOVE_TO_ABS
:
1852 case VG_CLOSE_PATH
: {
1853 VGfloat line
[4] = {prev_iter
.ox
, prev_iter
.oy
, iter
.sx
, iter
.sy
};
1854 VGboolean on_current_segment
= VG_FALSE
;
1855 *current_length
= line_lengthv(line
);
1856 on_current_segment
= point_on_current_segment(distance
,
1859 if (on_current_segment
) {
1860 VGfloat at
= (distance
- length
) / line_lengthv(line
);
1861 line_normal_vector(line
, normal
);
1862 line_point_at(line
, at
, point
);
1867 case VG_LINE_TO_ABS
: {
1868 VGfloat line
[4] = {prev_iter
.ox
, prev_iter
.oy
, coords
[0], coords
[1]};
1869 VGboolean on_current_segment
= VG_FALSE
;
1870 *current_length
= line_lengthv(line
);
1871 on_current_segment
= point_on_current_segment(distance
,
1874 if (on_current_segment
) {
1875 VGfloat at
= (distance
- length
) / line_lengthv(line
);
1876 line_normal_vector(line
, normal
);
1877 line_point_at(line
, at
, point
);
1882 case VG_CUBIC_TO_ABS
: {
1883 struct bezier bezier
;
1884 bezier_init(&bezier
, prev_iter
.ox
, prev_iter
.oy
,
1885 coords
[0], coords
[1],
1886 coords
[2], coords
[3],
1887 coords
[4], coords
[5]);
1888 *current_length
= bezier_length(&bezier
, BEZIER_DEFAULT_ERROR
);
1889 if (point_on_current_segment(distance
, length
, *current_length
)) {
1890 bezier_point_at_length(&bezier
, distance
- length
,
1899 case VG_LCWARC_TO
: {
1901 struct matrix identity
;
1902 struct path
*path
= path_create(VG_PATH_DATATYPE_F
,
1903 1, 0, 0, 0, VG_PATH_CAPABILITY_ALL
);
1905 matrix_load_identity(&identity
);
1906 arc_init(&arc
, iter
.segment
,
1907 prev_iter
.ox
, prev_iter
.oy
, coords
[3], coords
[4],
1908 coords
[0], coords
[1], coords
[2]);
1910 arc_to_path(&arc
, path
, &identity
);
1912 *current_length
= path_length(path
, 0, path_num_segments(path
));
1913 if (point_on_current_segment(distance
, length
, *current_length
)) {
1914 path_point(path
, 0, path_num_segments(path
),
1915 distance
- length
, point
, normal
);
1926 void path_point(struct path
*p
, VGint start_segment
, VGint num_segments
,
1927 VGfloat distance
, VGfloat
*point
, VGfloat
*normal
)
1931 struct path_iter_data iter
, prev_iter
;
1934 VGfloat current_length
= 0;
1936 memset(&iter
, 0, sizeof(struct path_iter_data
));
1937 memset(&prev_iter
, 0, sizeof(struct path_iter_data
));
1946 iter
.coords
= p
->control_points
->data
;
1950 for (i
= 0; i
< (start_segment
+ num_segments
); ++i
) {
1951 VGboolean outside_range
= (i
< start_segment
||
1952 i
>= (start_segment
+ num_segments
));
1956 iter
.segment
= ((VGubyte
*)(p
->segments
->data
))[i
];
1957 iter
.segment
= normalize_coords(&iter
, &num_coords
, coords
);
1962 if (path_point_segment(iter
, prev_iter
, coords
,
1963 distance
, length
, ¤t_length
,
1967 length
+= current_length
;
1971 *OpenVG 1.0 - 8.6.11 vgPointAlongPath
1973 * If distance is greater than or equal to the path length
1974 *(i.e., the value returned by vgPathLength when called with the same
1975 *startSegment and numSegments parameters), the visual ending point of
1979 switch (iter
.segment
) {
1980 case VG_MOVE_TO_ABS
:
1982 case VG_CLOSE_PATH
: {
1983 VGfloat line
[4] = {prev_iter
.ox
, prev_iter
.oy
, iter
.sx
, iter
.sy
};
1984 line_normal_vector(line
, normal
);
1985 line_point_at(line
, 1.f
, point
);
1988 case VG_LINE_TO_ABS
: {
1989 VGfloat line
[4] = {prev_iter
.ox
, prev_iter
.oy
, coords
[0], coords
[1]};
1990 line_normal_vector(line
, normal
);
1991 line_point_at(line
, 1.f
, point
);
1994 case VG_CUBIC_TO_ABS
: {
1995 struct bezier bezier
;
1996 bezier_init(&bezier
, prev_iter
.ox
, prev_iter
.oy
,
1997 coords
[0], coords
[1],
1998 coords
[2], coords
[3],
1999 coords
[4], coords
[5]);
2000 bezier_point_at_t(&bezier
, 1.f
, point
, normal
);
2006 case VG_LCWARC_TO
: {
2008 struct matrix identity
;
2009 struct path
*path
= path_create(VG_PATH_DATATYPE_F
,
2010 1, 0, 0, 0, VG_PATH_CAPABILITY_ALL
);
2012 matrix_load_identity(&identity
);
2013 arc_init(&arc
, iter
.segment
,
2014 prev_iter
.ox
, prev_iter
.oy
, coords
[3], coords
[4],
2015 coords
[0], coords
[1], coords
[2]);
2017 arc_to_path(&arc
, path
, &identity
);
2019 path_point(path
, 0, path_num_segments(path
),
2020 /* to make sure we're bigger than len * 2 it */
2021 2 * path_length(path
, 0, path_num_segments(path
)),
2031 VGboolean
path_is_empty(struct path
*p
)
2033 return p
->segments
->num_elements
== 0;