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(), &path
->base
);
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 static void polygon_array_cleanup(struct polygon_array
*polyarray
)
212 if (polyarray
->array
) {
215 for (i
= 0; i
< polyarray
->array
->num_elements
; i
++) {
216 struct polygon
*p
= ((struct polygon
**) polyarray
->array
->data
)[i
];
220 array_destroy(polyarray
->array
);
221 polyarray
->array
= NULL
;
225 void path_destroy(struct path
*p
)
227 vg_context_remove_object(vg_current_context(), &p
->base
);
229 array_destroy(p
->segments
);
230 array_destroy(p
->control_points
);
232 polygon_array_cleanup(&p
->fill_polys
.polygon_array
);
235 path_destroy(p
->stroked
.path
);
237 vg_free_object(&p
->base
);
242 VGbitfield
path_capabilities(struct path
*p
)
247 void path_set_capabilities(struct path
*p
, VGbitfield bf
)
249 p
->caps
= (bf
& VG_PATH_CAPABILITY_ALL
);
252 void path_append_data(struct path
*p
,
254 const VGubyte
* pathSegments
,
255 const void * pathData
)
257 VGint old_segments
= p
->num_segments
;
258 VGint num_new_coords
= num_elements_for_segments(pathSegments
, numSegments
);
259 array_append_data(p
->segments
, pathSegments
, numSegments
);
260 array_append_data(p
->control_points
, pathData
, num_new_coords
);
262 p
->num_segments
+= numSegments
;
263 if (!floatsEqual(p
->scale
, 1.f
) || !floatsEqual(p
->bias
, 0.f
)) {
264 VGubyte
*coords
= (VGubyte
*)p
->control_points
->data
;
265 coords_adjust_by_scale_bias(p
,
266 coords
+ old_segments
* p
->control_points
->datatype_size
,
268 p
->scale
, p
->bias
, p
->datatype
);
271 p
->dirty_stroke
= VG_TRUE
;
274 VGint
path_num_segments(struct path
*p
)
276 return p
->num_segments
;
279 static INLINE
void map_if_relative(VGfloat ox
, VGfloat oy
,
281 VGfloat
*x
, VGfloat
*y
)
291 static INLINE
void close_polygon(struct polygon
*current
,
292 VGfloat sx
, VGfloat sy
,
293 VGfloat ox
, VGfloat oy
,
294 struct matrix
*matrix
)
296 if (!floatsEqual(sx
, ox
) ||
297 !floatsEqual(sy
, oy
)) {
300 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
301 polygon_vertex_append(current
, x0
, y0
);
305 static void convert_path(struct path
*p
,
311 void *coords
= (VGfloat
*)p
->control_points
->data
;
312 VGubyte
*common_data
= (VGubyte
*)dst
;
313 VGint size_dst
= size_for_datatype(to
);
316 for (i
= 0; i
< num_coords
; ++i
) {
317 data_at(&coords
, p
, 0, 1, data
);
318 vg_float_to_datatype(to
, common_data
, data
, 1);
319 common_data
+= size_dst
;
323 static void polygon_array_calculate_bounds( struct polygon_array
*polyarray
)
325 struct array
*polys
= polyarray
->array
;
326 VGfloat min_x
, max_x
;
327 VGfloat min_y
, max_y
;
333 if (!polys
->num_elements
) {
334 polyarray
->min_x
= 0.0f
;
335 polyarray
->min_y
= 0.0f
;
336 polyarray
->max_x
= 0.0f
;
337 polyarray
->max_y
= 0.0f
;
341 polygon_bounding_rect((((struct polygon
**)polys
->data
)[0]), bounds
);
344 max_x
= bounds
[0] + bounds
[2];
345 max_y
= bounds
[1] + bounds
[3];
346 for (i
= 1; i
< polys
->num_elements
; ++i
) {
347 struct polygon
*p
= (((struct polygon
**)polys
->data
)[i
]);
348 polygon_bounding_rect(p
, bounds
);
349 min_x
= MIN2(min_x
, bounds
[0]);
350 min_y
= MIN2(min_y
, bounds
[1]);
351 max_x
= MAX2(max_x
, bounds
[0] + bounds
[2]);
352 max_y
= MAX2(max_y
, bounds
[1] + bounds
[3]);
355 polyarray
->min_x
= min_x
;
356 polyarray
->min_y
= min_y
;
357 polyarray
->max_x
= max_x
;
358 polyarray
->max_y
= max_y
;
362 static struct polygon_array
* path_get_fill_polygons(struct path
*p
, struct matrix
*matrix
)
365 struct polygon
*current
= 0;
366 VGfloat sx
, sy
, px
, py
, ox
, oy
;
367 VGfloat x0
, y0
, x1
, y1
, x2
, y2
, x3
, y3
;
369 void *coords
= (VGfloat
*)p
->control_points
->data
;
372 memset(data
, 0, sizeof(data
));
374 if (p
->fill_polys
.polygon_array
.array
)
376 if (memcmp( &p
->fill_polys
.matrix
,
378 sizeof *matrix
) == 0 && p
->dirty
== VG_FALSE
)
380 return &p
->fill_polys
.polygon_array
;
383 polygon_array_cleanup(&p
->fill_polys
.polygon_array
);
387 /* an array of pointers to polygons */
388 array
= array_create(sizeof(struct polygon
*));
390 sx
= sy
= px
= py
= ox
= oy
= 0.f
;
393 current
= polygon_create(32);
395 for (i
= 0; i
< p
->num_segments
; ++i
) {
396 VGubyte segment
= ((VGubyte
*)(p
->segments
->data
))[i
];
397 VGint command
= SEGMENT_COMMAND(segment
);
398 VGboolean relative
= SEGMENT_ABS_REL(segment
);
402 close_polygon(current
, sx
, sy
, ox
, oy
, matrix
);
407 if (current
&& polygon_vertex_count(current
) > 0) {
409 close_polygon(current
, sx
, sy
, ox
, oy
, matrix
);
410 array_append_data(array
, ¤t
, 1);
411 current
= polygon_create(32);
413 data_at(&coords
, p
, 0, 2, data
);
416 map_if_relative(ox
, oy
, relative
, &x0
, &y0
);
423 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
424 polygon_vertex_append(current
, x0
, y0
);
427 data_at(&coords
, p
, 0, 2, data
);
430 map_if_relative(ox
, oy
, relative
, &x0
, &y0
);
435 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
436 polygon_vertex_append(current
, x0
, y0
);
439 data_at(&coords
, p
, 0, 1, data
);
442 map_if_relative(ox
, oy
, relative
, &x0
, 0);
446 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
447 polygon_vertex_append(current
, x0
, y0
);
450 data_at(&coords
, p
, 0, 1, data
);
453 map_if_relative(ox
, oy
, relative
, 0, &y0
);
457 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
458 polygon_vertex_append(current
, x0
, y0
);
461 struct bezier bezier
;
462 data_at(&coords
, p
, 0, 6, data
);
471 map_if_relative(ox
, oy
, relative
, &x1
, &y1
);
472 map_if_relative(ox
, oy
, relative
, &x2
, &y2
);
473 map_if_relative(ox
, oy
, relative
, &x3
, &y3
);
478 assert(matrix_is_affine(matrix
));
479 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
480 matrix_map_point(matrix
, x1
, y1
, &x1
, &y1
);
481 matrix_map_point(matrix
, x2
, y2
, &x2
, &y2
);
482 matrix_map_point(matrix
, x3
, y3
, &x3
, &y3
);
483 bezier_init(&bezier
, x0
, y0
, x1
, y1
,
485 bezier_add_to_polygon(&bezier
, current
);
489 struct bezier bezier
;
490 data_at(&coords
, p
, 0, 4, data
);
497 map_if_relative(ox
, oy
, relative
, &x1
, &y1
);
498 map_if_relative(ox
, oy
, relative
, &x3
, &y3
);
501 { /* form a cubic out of it */
502 x2
= (x3
+ 2*x1
) / 3.f
;
503 y2
= (y3
+ 2*y1
) / 3.f
;
504 x1
= (x0
+ 2*x1
) / 3.f
;
505 y1
= (y0
+ 2*y1
) / 3.f
;
509 assert(matrix_is_affine(matrix
));
510 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
511 matrix_map_point(matrix
, x1
, y1
, &x1
, &y1
);
512 matrix_map_point(matrix
, x2
, y2
, &x2
, &y2
);
513 matrix_map_point(matrix
, x3
, y3
, &x3
, &y3
);
514 bezier_init(&bezier
, x0
, y0
, x1
, y1
,
516 bezier_add_to_polygon(&bezier
, current
);
520 struct bezier bezier
;
521 data_at(&coords
, p
, 0, 2, data
);
528 map_if_relative(ox
, oy
, relative
, &x3
, &y3
);
531 { /* form a cubic out of it */
532 x2
= (x3
+ 2*x1
) / 3.f
;
533 y2
= (y3
+ 2*y1
) / 3.f
;
534 x1
= (x0
+ 2*x1
) / 3.f
;
535 y1
= (y0
+ 2*y1
) / 3.f
;
539 assert(matrix_is_affine(matrix
));
540 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
541 matrix_map_point(matrix
, x1
, y1
, &x1
, &y1
);
542 matrix_map_point(matrix
, x2
, y2
, &x2
, &y2
);
543 matrix_map_point(matrix
, x3
, y3
, &x3
, &y3
);
544 bezier_init(&bezier
, x0
, y0
, x1
, y1
,
546 bezier_add_to_polygon(&bezier
, current
);
550 struct bezier bezier
;
551 data_at(&coords
, p
, 0, 4, data
);
560 map_if_relative(ox
, oy
, relative
, &x2
, &y2
);
561 map_if_relative(ox
, oy
, relative
, &x3
, &y3
);
566 assert(matrix_is_affine(matrix
));
567 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
568 matrix_map_point(matrix
, x1
, y1
, &x1
, &y1
);
569 matrix_map_point(matrix
, x2
, y2
, &x2
, &y2
);
570 matrix_map_point(matrix
, x3
, y3
, &x3
, &y3
);
571 bezier_init(&bezier
, x0
, y0
, x1
, y1
,
573 bezier_add_to_polygon(&bezier
, current
);
583 data_at(&coords
, p
, 0, 5, data
);
591 map_if_relative(ox
, oy
, relative
, &x1
, &y1
);
593 debug_printf("------- ARC (%f, %f), (%f, %f) %f, %f, %f\n",
594 x0
, y0
, x1
, y1
, rh
, rv
, rot
);
596 arc_init(&arc
, command
, x0
, y0
, x1
, y1
,
598 arc_add_to_polygon(&arc
, current
,
608 assert(!"Unknown segment!");
612 if (polygon_vertex_count(current
) > 0) {
613 close_polygon(current
, sx
, sy
, ox
, oy
, matrix
);
614 array_append_data(array
, ¤t
, 1);
616 polygon_destroy(current
);
619 p
->fill_polys
.polygon_array
.array
= array
;
620 p
->fill_polys
.matrix
= *matrix
;
622 polygon_array_calculate_bounds( &p
->fill_polys
.polygon_array
);
626 return &p
->fill_polys
.polygon_array
;
629 VGbyte
path_datatype_size(struct path
*p
)
631 return size_for_datatype(p
->datatype
);
634 VGPathDatatype
path_datatype(struct path
*p
)
639 VGfloat
path_scale(struct path
*p
)
644 VGfloat
path_bias(struct path
*p
)
649 VGint
path_num_coords(struct path
*p
)
651 return num_elements_for_segments((VGubyte
*)p
->segments
->data
,
655 void path_modify_coords(struct path
*p
,
658 const void * pathData
)
660 VGubyte
*segments
= (VGubyte
*)(p
->segments
->data
);
661 VGint count
= num_elements_for_segments(&segments
[startIndex
], numSegments
);
662 VGint start_cp
= num_elements_for_segments(segments
, startIndex
);
664 array_change_data(p
->control_points
, pathData
, start_cp
, count
);
665 coords_adjust_by_scale_bias(p
,
666 ((VGubyte
*)p
->control_points
->data
) +
667 (startIndex
* p
->control_points
->datatype_size
),
669 p
->scale
, p
->bias
, p
->datatype
);
671 p
->dirty_stroke
= VG_TRUE
;
674 void path_for_each_segment(struct path
*path
,
679 struct path_for_each_data p
;
681 void *coords
= (VGfloat
*)path
->control_points
->data
;
684 p
.sx
= p
.sy
= p
.px
= p
.py
= p
.ox
= p
.oy
= 0.f
;
685 p
.user_data
= user_data
;
687 for (i
= 0; i
< path
->num_segments
; ++i
) {
691 p
.segment
= ((VGubyte
*)(path
->segments
->data
))[i
];
692 command
= SEGMENT_COMMAND(p
.segment
);
693 relative
= SEGMENT_ABS_REL(p
.segment
);
700 data_at(&coords
, path
, 0, 2, data
);
701 map_if_relative(p
.ox
, p
.oy
, relative
, &data
[0], &data
[1]);
711 data_at(&coords
, path
, 0, 2, data
);
712 map_if_relative(p
.ox
, p
.oy
, relative
, &data
[0], &data
[1]);
720 data_at(&coords
, path
, 0, 1, data
);
721 map_if_relative(p
.ox
, p
.oy
, relative
, &data
[0], 0);
722 p
.segment
= VG_LINE_TO
;
731 data_at(&coords
, path
, 0, 1, data
);
732 map_if_relative(p
.ox
, p
.oy
, relative
, 0, &data
[0]);
733 p
.segment
= VG_LINE_TO
;
743 data_at(&coords
, path
, 0, 6, data
);
744 map_if_relative(p
.ox
, p
.oy
, relative
, &data
[0], &data
[1]);
745 map_if_relative(p
.ox
, p
.oy
, relative
, &data
[2], &data
[3]);
746 map_if_relative(p
.ox
, p
.oy
, relative
, &data
[4], &data
[5]);
755 data_at(&coords
, path
, 0, 4, data
);
756 map_if_relative(p
.ox
, p
.oy
, relative
, &data
[0], &data
[1]);
757 map_if_relative(p
.ox
, p
.oy
, relative
, &data
[2], &data
[3]);
766 data_at(&coords
, path
, 0, 2, data
);
767 map_if_relative(p
.ox
, p
.oy
, relative
, &data
[0], &data
[1]);
776 data_at(&coords
, path
, 0, 4, data
);
777 map_if_relative(p
.ox
, p
.oy
, relative
, &data
[0], &data
[1]);
778 map_if_relative(p
.ox
, p
.oy
, relative
, &data
[2], &data
[3]);
790 data_at(&coords
, path
, 0, 5, data
);
791 map_if_relative(p
.ox
, p
.oy
, relative
, &data
[3], &data
[4]);
793 debug_printf("------- ARC (%f, %f), (%f, %f) %f, %f, %f\n",
794 p
.ox
, p
.oy
, data
[3], data
[4], data
[0], data
[1], data
[2]);
805 assert(!"Unknown segment!");
810 struct transform_data
{
811 struct array
*segments
;
812 struct array
*coords
;
814 struct matrix
*matrix
;
816 VGPathDatatype datatype
;
819 static VGboolean
transform_cb(struct path
*p
,
820 struct path_for_each_data
*pd
)
822 struct transform_data
*td
= (struct transform_data
*)pd
->user_data
;
823 VGint num_coords
= num_elements_for_segments(&pd
->segment
, 1);
824 VGubyte segment
= SEGMENT_COMMAND(pd
->segment
);/* abs bit is 0 */
826 VGubyte common_data
[sizeof(VGfloat
)*8];
828 memcpy(data
, pd
->coords
, sizeof(VGfloat
) * num_coords
);
834 matrix_map_point(td
->matrix
,
835 data
[0], data
[1], &data
[0], &data
[1]);
838 matrix_map_point(td
->matrix
,
839 data
[0], data
[1], &data
[0], &data
[1]);
846 matrix_map_point(td
->matrix
,
847 data
[0], data
[1], &data
[0], &data
[1]);
848 matrix_map_point(td
->matrix
,
849 data
[2], data
[3], &data
[2], &data
[3]);
852 matrix_map_point(td
->matrix
,
853 data
[0], data
[1], &data
[0], &data
[1]);
854 matrix_map_point(td
->matrix
,
855 data
[2], data
[3], &data
[2], &data
[3]);
856 matrix_map_point(td
->matrix
,
857 data
[4], data
[5], &data
[4], &data
[5]);
860 matrix_map_point(td
->matrix
,
861 data
[0], data
[1], &data
[0], &data
[1]);
864 matrix_map_point(td
->matrix
,
865 data
[0], data
[1], &data
[0], &data
[1]);
866 matrix_map_point(td
->matrix
,
867 data
[2], data
[3], &data
[2], &data
[3]);
874 struct path
*path
= path_create(td
->datatype
,
875 1, 0, 0, 0, VG_PATH_CAPABILITY_ALL
);
876 arc_init(&arc
, segment
,
877 pd
->ox
, pd
->oy
, data
[3], data
[4],
878 data
[0], data
[1], data
[2]);
880 arc_to_path(&arc
, path
, td
->matrix
);
882 num_coords
= path_num_coords(path
);
884 array_append_data(td
->segments
, path
->segments
->data
,
886 array_append_data(td
->coords
, path
->control_points
->data
,
897 vg_float_to_datatype(td
->datatype
, common_data
, data
, num_coords
);
899 array_append_data(td
->segments
, &pd
->segment
, 1);
900 array_append_data(td
->coords
, common_data
, num_coords
);
904 void path_transform(struct path
*dst
, struct path
*src
)
906 struct transform_data data
;
907 struct vg_context
*ctx
= dst
->base
.ctx
;
909 data
.segments
= dst
->segments
;
910 data
.coords
= dst
->control_points
;
911 data
.matrix
= &ctx
->state
.vg
.path_user_to_surface_matrix
;
912 data
.datatype
= dst
->datatype
;
914 path_for_each_segment(src
, transform_cb
, (void*)&data
);
916 dst
->num_segments
= dst
->segments
->num_elements
;
917 dst
->dirty
= VG_TRUE
;
918 dst
->dirty_stroke
= VG_TRUE
;
921 void path_append_path(struct path
*dst
,
924 VGint num_coords
= path_num_coords(src
);
925 void *dst_data
= malloc(size_for_datatype(dst
->datatype
) * num_coords
);
926 array_append_data(dst
->segments
,
929 convert_path(src
, dst
->datatype
,
930 dst_data
, num_coords
);
931 array_append_data(dst
->control_points
,
936 dst
->num_segments
+= src
->num_segments
;
937 dst
->dirty
= VG_TRUE
;
938 dst
->dirty_stroke
= VG_TRUE
;
941 static INLINE VGboolean
is_segment_arc(VGubyte segment
)
943 VGubyte scommand
= SEGMENT_COMMAND(segment
);
944 return (scommand
== VG_SCCWARC_TO
||
945 scommand
== VG_SCWARC_TO
||
946 scommand
== VG_LCCWARC_TO
||
947 scommand
== VG_LCWARC_TO
);
950 struct path_iter_data
{
954 VGfloat px
, py
, ox
, oy
, sx
, sy
;
956 static INLINE VGubyte
normalize_coords(struct path_iter_data
*pd
,
960 VGint command
= SEGMENT_COMMAND(pd
->segment
);
961 VGboolean relative
= SEGMENT_ABS_REL(pd
->segment
);
968 return VG_CLOSE_PATH
;
971 data_at(&pd
->coords
, pd
->path
, 0, 2, data
);
972 map_if_relative(pd
->ox
, pd
->oy
, relative
, &data
[0], &data
[1]);
980 return VG_MOVE_TO_ABS
;
983 data_at(&pd
->coords
, pd
->path
, 0, 2, data
);
984 map_if_relative(pd
->ox
, pd
->oy
, relative
, &data
[0], &data
[1]);
990 return VG_LINE_TO_ABS
;
993 data_at(&pd
->coords
, pd
->path
, 0, 1, data
);
994 map_if_relative(pd
->ox
, pd
->oy
, relative
, &data
[0], 0);
1001 return VG_LINE_TO_ABS
;
1004 data_at(&pd
->coords
, pd
->path
, 0, 1, data
);
1005 map_if_relative(pd
->ox
, pd
->oy
, relative
, 0, &data
[0]);
1013 return VG_LINE_TO_ABS
;
1016 data_at(&pd
->coords
, pd
->path
, 0, 6, data
);
1017 map_if_relative(pd
->ox
, pd
->oy
, relative
, &data
[0], &data
[1]);
1018 map_if_relative(pd
->ox
, pd
->oy
, relative
, &data
[2], &data
[3]);
1019 map_if_relative(pd
->ox
, pd
->oy
, relative
, &data
[4], &data
[5]);
1025 return VG_CUBIC_TO_ABS
;
1029 VGfloat x0
, y0
, x1
, y1
, x2
, y2
, x3
, y3
;
1030 data_at(&pd
->coords
, pd
->path
, 0, 4, data
);
1037 map_if_relative(pd
->ox
, pd
->oy
, relative
, &x1
, &y1
);
1038 map_if_relative(pd
->ox
, pd
->oy
, relative
, &x3
, &y3
);
1041 { /* form a cubic out of it */
1042 x2
= (x3
+ 2*x1
) / 3.f
;
1043 y2
= (y3
+ 2*y1
) / 3.f
;
1044 x1
= (x0
+ 2*x1
) / 3.f
;
1045 y1
= (y0
+ 2*y1
) / 3.f
;
1056 return VG_CUBIC_TO_ABS
;
1060 VGfloat x0
, y0
, x1
, y1
, x2
, y2
, x3
, y3
;
1061 data_at(&pd
->coords
, pd
->path
, 0, 2, data
);
1064 x1
= 2 * pd
->ox
- pd
->px
;
1065 y1
= 2 * pd
->oy
- pd
->py
;
1068 map_if_relative(pd
->ox
, pd
->oy
, relative
, &x3
, &y3
);
1071 { /* form a cubic out of it */
1072 x2
= (x3
+ 2*x1
) / 3.f
;
1073 y2
= (y3
+ 2*y1
) / 3.f
;
1074 x1
= (x0
+ 2*x1
) / 3.f
;
1075 y1
= (y0
+ 2*y1
) / 3.f
;
1086 return VG_CUBIC_TO_ABS
;
1089 case VG_SCUBIC_TO
: {
1090 VGfloat x1
, y1
, x2
, y2
, x3
, y3
;
1091 data_at(&pd
->coords
, pd
->path
, 0, 4, data
);
1092 x1
= 2*pd
->ox
-pd
->px
;
1093 y1
= 2*pd
->oy
-pd
->py
;
1098 map_if_relative(pd
->ox
, pd
->oy
, relative
, &x2
, &y2
);
1099 map_if_relative(pd
->ox
, pd
->oy
, relative
, &x3
, &y3
);
1111 return VG_CUBIC_TO_ABS
;
1117 case VG_LCWARC_TO
: {
1118 data_at(&pd
->coords
, pd
->path
, 0, 5, data
);
1119 map_if_relative(pd
->ox
, pd
->oy
, relative
, &data
[3], &data
[4]);
1125 return command
| VG_ABSOLUTE
;
1130 assert(!"Unknown segment!");
1134 static void linearly_interpolate(VGfloat
*result
,
1135 const VGfloat
*start
,
1141 for (i
= 0; i
< number
; ++i
) {
1142 result
[i
] = start
[i
] + (end
[i
] - start
[i
]) * amount
;
1146 VGboolean
path_interpolate(struct path
*dst
,
1147 struct path
*start
, struct path
*end
,
1150 /* temporary path that we can discard if it will turn
1151 * out that start is not compatible with end */
1152 struct path
*res_path
= path_create(dst
->datatype
,
1156 VGfloat start_coords
[8];
1157 VGfloat end_coords
[8];
1159 VGubyte common_data
[sizeof(VGfloat
)*8];
1160 struct path_iter_data start_iter
, end_iter
;
1162 memset(&start_iter
, 0, sizeof(struct path_iter_data
));
1163 memset(&end_iter
, 0, sizeof(struct path_iter_data
));
1165 start_iter
.path
= start
;
1166 start_iter
.coords
= start
->control_points
->data
;
1167 end_iter
.path
= end
;
1168 end_iter
.coords
= end
->control_points
->data
;
1170 for (i
= 0; i
< start
->num_segments
; ++i
) {
1172 VGubyte ssegment
, esegment
;
1173 VGint snum_coords
, enum_coords
;
1174 start_iter
.segment
= ((VGubyte
*)(start
->segments
->data
))[i
];
1175 end_iter
.segment
= ((VGubyte
*)(end
->segments
->data
))[i
];
1177 ssegment
= normalize_coords(&start_iter
, &snum_coords
,
1179 esegment
= normalize_coords(&end_iter
, &enum_coords
,
1182 if (is_segment_arc(ssegment
)) {
1183 if (!is_segment_arc(esegment
)) {
1184 path_destroy(res_path
);
1191 } else if (is_segment_arc(esegment
)) {
1192 path_destroy(res_path
);
1195 else if (ssegment
!= esegment
) {
1196 path_destroy(res_path
);
1202 linearly_interpolate(results
, start_coords
, end_coords
,
1203 amount
, snum_coords
);
1204 vg_float_to_datatype(dst
->datatype
, common_data
, results
, snum_coords
);
1205 path_append_data(res_path
, 1, &segment
, common_data
);
1208 path_append_path(dst
, res_path
);
1209 path_destroy(res_path
);
1211 dst
->dirty
= VG_TRUE
;
1212 dst
->dirty_stroke
= VG_TRUE
;
1217 void path_clear(struct path
*p
, VGbitfield capabilities
)
1219 path_set_capabilities(p
, capabilities
);
1220 array_destroy(p
->segments
);
1221 array_destroy(p
->control_points
);
1222 p
->segments
= array_create(size_for_datatype(VG_PATH_DATATYPE_S_8
));
1223 p
->control_points
= array_create(size_for_datatype(p
->datatype
));
1224 p
->num_segments
= 0;
1226 p
->dirty_stroke
= VG_TRUE
;
1229 struct path
* path_create_stroke(struct path
*p
,
1230 struct matrix
*matrix
)
1233 VGfloat sx
, sy
, px
, py
, ox
, oy
;
1234 VGfloat x0
, y0
, x1
, y1
, x2
, y2
, x3
, y3
;
1236 void *coords
= (VGfloat
*)p
->control_points
->data
;
1237 int dashed
= (p
->base
.ctx
->state
.vg
.stroke
.dash_pattern_num
? 1 : 0);
1238 struct dash_stroker stroker
;
1239 struct vg_state
*vg_state
= &p
->base
.ctx
->state
.vg
;
1241 if (p
->stroked
.path
)
1243 /* ### compare the dash patterns to see if we can cache them.
1244 * for now we simply always bail out if the path is dashed.
1246 if (memcmp( &p
->stroked
.matrix
,
1248 sizeof *matrix
) == 0 &&
1249 !dashed
&& !p
->dirty_stroke
&&
1250 floatsEqual(p
->stroked
.stroke_width
, vg_state
->stroke
.line_width
.f
) &&
1251 floatsEqual(p
->stroked
.miter_limit
, vg_state
->stroke
.miter_limit
.f
) &&
1252 p
->stroked
.cap_style
== vg_state
->stroke
.cap_style
&&
1253 p
->stroked
.join_style
== vg_state
->stroke
.join_style
)
1255 return p
->stroked
.path
;
1258 path_destroy( p
->stroked
.path
);
1259 p
->stroked
.path
= NULL
;
1264 sx
= sy
= px
= py
= ox
= oy
= 0.f
;
1267 dash_stroker_init((struct stroker
*)&stroker
, vg_state
);
1269 stroker_init((struct stroker
*)&stroker
, vg_state
);
1271 stroker_begin((struct stroker
*)&stroker
);
1273 for (i
= 0; i
< p
->num_segments
; ++i
) {
1274 VGubyte segment
= ((VGubyte
*)(p
->segments
->data
))[i
];
1275 VGint command
= SEGMENT_COMMAND(segment
);
1276 VGboolean relative
= SEGMENT_ABS_REL(segment
);
1279 case VG_CLOSE_PATH
: {
1282 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
1283 stroker_line_to((struct stroker
*)&stroker
, x0
, y0
);
1287 data_at(&coords
, p
, 0, 2, data
);
1290 map_if_relative(ox
, oy
, relative
, &x0
, &y0
);
1297 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
1298 stroker_move_to((struct stroker
*)&stroker
, x0
, y0
);
1301 data_at(&coords
, p
, 0, 2, data
);
1304 map_if_relative(ox
, oy
, relative
, &x0
, &y0
);
1309 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
1310 stroker_line_to((struct stroker
*)&stroker
, x0
, y0
);
1313 data_at(&coords
, p
, 0, 1, data
);
1316 map_if_relative(ox
, oy
, relative
, &x0
, 0);
1320 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
1321 stroker_line_to((struct stroker
*)&stroker
, x0
, y0
);
1324 data_at(&coords
, p
, 0, 1, data
);
1327 map_if_relative(ox
, oy
, relative
, 0, &y0
);
1331 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
1332 stroker_line_to((struct stroker
*)&stroker
, x0
, y0
);
1335 data_at(&coords
, p
, 0, 6, data
);
1344 map_if_relative(ox
, oy
, relative
, &x1
, &y1
);
1345 map_if_relative(ox
, oy
, relative
, &x2
, &y2
);
1346 map_if_relative(ox
, oy
, relative
, &x3
, &y3
);
1347 if (floatsEqual(x1
, ox
) && floatsEqual(y1
, oy
) &&
1348 floatsEqual(x1
, x2
) && floatsEqual(y1
, y2
) &&
1349 floatsEqual(x2
, x3
) && floatsEqual(y2
, y3
)) {
1350 /*ignore the empty segment */
1352 } else if (floatsEqual(x3
, ox
) && floatsEqual(y3
, oy
)) {
1353 /* if dup vertex, emit a line */
1356 matrix_map_point(matrix
, x3
, y3
, &x3
, &y3
);
1357 stroker_line_to((struct stroker
*)&stroker
, x3
, y3
);
1364 assert(matrix_is_affine(matrix
));
1365 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
1366 matrix_map_point(matrix
, x1
, y1
, &x1
, &y1
);
1367 matrix_map_point(matrix
, x2
, y2
, &x2
, &y2
);
1368 matrix_map_point(matrix
, x3
, y3
, &x3
, &y3
);
1369 stroker_curve_to((struct stroker
*)&stroker
, x1
, y1
, x2
, y2
, x3
, y3
);
1373 data_at(&coords
, p
, 0, 4, data
);
1380 map_if_relative(ox
, oy
, relative
, &x1
, &y1
);
1381 map_if_relative(ox
, oy
, relative
, &x3
, &y3
);
1384 { /* form a cubic out of it */
1385 x2
= (x3
+ 2*x1
) / 3.f
;
1386 y2
= (y3
+ 2*y1
) / 3.f
;
1387 x1
= (x0
+ 2*x1
) / 3.f
;
1388 y1
= (y0
+ 2*y1
) / 3.f
;
1390 if (floatsEqual(x1
, ox
) && floatsEqual(y1
, oy
) &&
1391 floatsEqual(x1
, x2
) && floatsEqual(y1
, y2
) &&
1392 floatsEqual(x2
, x3
) && floatsEqual(y2
, y3
)) {
1393 /*ignore the empty segment */
1395 } else if (floatsEqual(x3
, ox
) && floatsEqual(y3
, oy
)) {
1396 /* if dup vertex, emit a line */
1399 matrix_map_point(matrix
, x3
, y3
, &x3
, &y3
);
1400 stroker_line_to((struct stroker
*)&stroker
, x3
, y3
);
1405 assert(matrix_is_affine(matrix
));
1406 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
1407 matrix_map_point(matrix
, x1
, y1
, &x1
, &y1
);
1408 matrix_map_point(matrix
, x2
, y2
, &x2
, &y2
);
1409 matrix_map_point(matrix
, x3
, y3
, &x3
, &y3
);
1410 stroker_curve_to((struct stroker
*)&stroker
, x1
, y1
, x2
, y2
, x3
, y3
);
1414 data_at(&coords
, p
, 0, 2, data
);
1421 map_if_relative(ox
, oy
, relative
, &x3
, &y3
);
1424 { /* form a cubic out of it */
1425 x2
= (x3
+ 2*x1
) / 3.f
;
1426 y2
= (y3
+ 2*y1
) / 3.f
;
1427 x1
= (x0
+ 2*x1
) / 3.f
;
1428 y1
= (y0
+ 2*y1
) / 3.f
;
1430 if (floatsEqual(x1
, ox
) && floatsEqual(y1
, oy
) &&
1431 floatsEqual(x1
, x2
) && floatsEqual(y1
, y2
) &&
1432 floatsEqual(x2
, x3
) && floatsEqual(y2
, y3
)) {
1433 /*ignore the empty segment */
1435 } else if (floatsEqual(x3
, ox
) && floatsEqual(y3
, oy
)) {
1436 /* if dup vertex, emit a line */
1439 matrix_map_point(matrix
, x3
, y3
, &x3
, &y3
);
1440 stroker_line_to((struct stroker
*)&stroker
, x3
, y3
);
1445 assert(matrix_is_affine(matrix
));
1446 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
1447 matrix_map_point(matrix
, x1
, y1
, &x1
, &y1
);
1448 matrix_map_point(matrix
, x2
, y2
, &x2
, &y2
);
1449 matrix_map_point(matrix
, x3
, y3
, &x3
, &y3
);
1450 stroker_curve_to((struct stroker
*)&stroker
, x1
, y1
, x2
, y2
, x3
, y3
);
1453 case VG_SCUBIC_TO
: {
1454 data_at(&coords
, p
, 0, 4, data
);
1463 map_if_relative(ox
, oy
, relative
, &x2
, &y2
);
1464 map_if_relative(ox
, oy
, relative
, &x3
, &y3
);
1465 if (floatsEqual(x1
, ox
) && floatsEqual(y1
, oy
) &&
1466 floatsEqual(x1
, x2
) && floatsEqual(y1
, y2
) &&
1467 floatsEqual(x2
, x3
) && floatsEqual(y2
, y3
)) {
1468 /*ignore the empty segment */
1470 } else if (floatsEqual(x3
, ox
) && floatsEqual(y3
, oy
)) {
1471 /* if dup vertex, emit a line */
1474 matrix_map_point(matrix
, x3
, y3
, &x3
, &y3
);
1475 stroker_line_to((struct stroker
*)&stroker
, x3
, y3
);
1482 assert(matrix_is_affine(matrix
));
1483 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
1484 matrix_map_point(matrix
, x1
, y1
, &x1
, &y1
);
1485 matrix_map_point(matrix
, x2
, y2
, &x2
, &y2
);
1486 matrix_map_point(matrix
, x3
, y3
, &x3
, &y3
);
1487 stroker_curve_to((struct stroker
*)&stroker
, x1
, y1
, x2
, y2
, x3
, y3
);
1493 case VG_LCWARC_TO
: {
1494 VGfloat rh
, rv
, rot
;
1497 data_at(&coords
, p
, 0, 5, data
);
1505 map_if_relative(ox
, oy
, relative
, &x1
, &y1
);
1506 if (floatsEqual(x1
, ox
) && floatsEqual(y1
, oy
)) {
1507 /* if dup vertex, emit a line */
1510 matrix_map_point(matrix
, x1
, y1
, &x1
, &y1
);
1511 stroker_line_to((struct stroker
*)&stroker
, x1
, y1
);
1514 arc_init(&arc
, command
, x0
, y0
, x1
, y1
,
1516 arc_stroke_cb(&arc
, (struct stroker
*)&stroker
,
1526 assert(!"Unknown segment!");
1530 stroker_end((struct stroker
*)&stroker
);
1533 dash_stroker_cleanup((struct dash_stroker
*)&stroker
);
1535 stroker_cleanup((struct stroker
*)&stroker
);
1537 p
->stroked
.path
= stroker
.base
.path
;
1538 p
->stroked
.matrix
= *matrix
;
1539 p
->dirty_stroke
= VG_FALSE
;
1540 p
->stroked
.stroke_width
= vg_state
->stroke
.line_width
.f
;
1541 p
->stroked
.miter_limit
= vg_state
->stroke
.miter_limit
.f
;
1542 p
->stroked
.cap_style
= vg_state
->stroke
.cap_style
;
1543 p
->stroked
.join_style
= vg_state
->stroke
.join_style
;
1545 return stroker
.base
.path
;
1548 void path_render(struct path
*p
, VGbitfield paintModes
,
1551 struct vg_context
*ctx
= vg_current_context();
1552 struct matrix paint_matrix
;
1554 vg_validate_state(ctx
);
1556 shader_set_drawing_image(ctx
->shader
, VG_FALSE
);
1557 shader_set_image(ctx
->shader
, 0);
1559 fprintf(stderr
, "Matrix(11=%f 12=%f 13=%f 21=%f 22=%f 23=%f 31=%f 32=%f 33=%f)\n",
1560 mat
->m
[0], mat
->m
[1], mat
->m
[2],
1561 mat
->m
[3], mat
->m
[4], mat
->m
[5],
1562 mat
->m
[6], mat
->m
[7], mat
->m
[8]);
1564 if ((paintModes
& VG_FILL_PATH
) &&
1565 vg_get_paint_matrix(ctx
,
1566 &ctx
->state
.vg
.fill_paint_to_user_matrix
,
1569 /* First the fill */
1570 shader_set_surface_matrix(ctx
->shader
, mat
);
1571 shader_set_paint(ctx
->shader
, ctx
->state
.vg
.fill_paint
);
1572 shader_set_paint_matrix(ctx
->shader
, &paint_matrix
);
1573 shader_bind(ctx
->shader
);
1577 if ((paintModes
& VG_STROKE_PATH
) &&
1578 vg_get_paint_matrix(ctx
,
1579 &ctx
->state
.vg
.stroke_paint_to_user_matrix
,
1582 /* 8.7.5: "line width less than or equal to 0 prevents stroking from
1584 if (ctx
->state
.vg
.stroke
.line_width
.f
<= 0)
1586 shader_set_surface_matrix(ctx
->shader
, mat
);
1587 shader_set_paint(ctx
->shader
, ctx
->state
.vg
.stroke_paint
);
1588 shader_set_paint_matrix(ctx
->shader
, &paint_matrix
);
1589 shader_bind(ctx
->shader
);
1594 void path_fill(struct path
*p
)
1596 struct vg_context
*ctx
= vg_current_context();
1597 struct matrix identity
;
1599 matrix_load_identity(&identity
);
1602 struct polygon_array
*polygon_array
= path_get_fill_polygons(p
, &identity
);
1603 struct array
*polys
= polygon_array
->array
;
1605 if (!polygon_array
|| !polys
|| !polys
->num_elements
) {
1608 polygon_array_fill(polygon_array
, ctx
);
1612 void path_stroke(struct path
*p
)
1614 struct vg_context
*ctx
= vg_current_context();
1615 VGFillRule old_fill
= ctx
->state
.vg
.fill_rule
;
1616 struct matrix identity
;
1617 struct path
*stroke
;
1619 matrix_load_identity(&identity
);
1620 stroke
= path_create_stroke(p
, &identity
);
1621 if (stroke
&& !path_is_empty(stroke
)) {
1622 ctx
->state
.vg
.fill_rule
= VG_NON_ZERO
;
1626 ctx
->state
.vg
.fill_rule
= old_fill
;
1630 void path_move_to(struct path
*p
, float x
, float y
)
1632 VGubyte segment
= VG_MOVE_TO_ABS
;
1633 VGubyte common_data
[sizeof(VGfloat
) * 2];
1634 VGfloat data
[2] = {x
, y
};
1636 vg_float_to_datatype(p
->datatype
, common_data
, data
, 2);
1637 path_append_data(p
, 1, &segment
, common_data
);
1640 void path_line_to(struct path
*p
, float x
, float y
)
1642 VGubyte segment
= VG_LINE_TO_ABS
;
1643 VGubyte common_data
[sizeof(VGfloat
) * 2];
1644 VGfloat data
[2] = {x
, y
};
1646 vg_float_to_datatype(p
->datatype
, common_data
, data
, 2);
1648 path_append_data(p
, 1, &segment
, common_data
);
1651 void path_cubic_to(struct path
*p
, float px1
, float py1
,
1652 float px2
, float py2
,
1655 VGubyte segment
= VG_CUBIC_TO_ABS
;
1656 VGubyte common_data
[sizeof(VGfloat
) * 6];
1659 data
[0] = px1
; data
[1] = py1
;
1660 data
[2] = px2
; data
[3] = py2
;
1661 data
[4] = x
; data
[5] = y
;
1663 vg_float_to_datatype(p
->datatype
, common_data
, data
, 6);
1665 path_append_data(p
, 1, &segment
, common_data
);
1668 static INLINE
void line_bounds(VGfloat
*line
/*x1,y1,x2,y2*/,
1671 bounds
[0] = MIN2(line
[0], line
[2]);
1672 bounds
[1] = MIN2(line
[1], line
[3]);
1673 bounds
[2] = MAX2(line
[0], line
[2]) - bounds
[0];
1674 bounds
[3] = MAX2(line
[1], line
[3]) - bounds
[1];
1677 static INLINE
void unite_bounds(VGfloat
*bounds
,
1680 VGfloat cx1
, cy1
, cx2
, cy2
;
1681 VGfloat nx1
, ny1
, nx2
, ny2
;
1685 cx2
= bounds
[0] + bounds
[2];
1686 cy2
= bounds
[1] + bounds
[3];
1690 nx2
= el
[0] + el
[2];
1691 ny2
= el
[1] + el
[3];
1693 bounds
[0] = MIN2(cx1
, nx1
);
1694 bounds
[1] = MIN2(cy1
, ny1
);
1695 bounds
[2] = MAX2(cx2
, nx2
) - bounds
[0];
1696 bounds
[3] = MAX2(cy2
, ny2
) - bounds
[1];
1699 static INLINE
void set_bounds(VGfloat
*bounds
,
1700 VGfloat
*element_bounds
,
1701 VGboolean
*initialized
)
1703 if (!(*initialized
)) {
1704 memcpy(bounds
, element_bounds
, 4 * sizeof(VGfloat
));
1705 *initialized
= VG_TRUE
;
1707 unite_bounds(bounds
, element_bounds
);
1710 void path_bounding_rect(struct path
*p
, float *x
, float *y
,
1715 struct path_iter_data iter
;
1718 VGfloat element_bounds
[4];
1720 VGboolean bounds_inited
= VG_FALSE
;
1722 memset(&iter
, 0, sizeof(struct path_iter_data
));
1723 memset(&bounds
, 0, sizeof(bounds
));
1725 if (!p
->num_segments
) {
1732 iter
.coords
= p
->control_points
->data
;
1734 for (i
= 0; i
< p
->num_segments
; ++i
) {
1736 iter
.segment
= ((VGubyte
*)(p
->segments
->data
))[i
];
1741 segment
= normalize_coords(&iter
, &num_coords
, coords
);
1745 case VG_MOVE_TO_ABS
:
1747 case VG_LINE_TO_ABS
: {
1748 VGfloat line
[4] = {ox
, oy
, coords
[0], coords
[1]};
1749 line_bounds(line
, element_bounds
);
1750 set_bounds(bounds
, element_bounds
, &bounds_inited
);
1753 case VG_CUBIC_TO_ABS
: {
1754 struct bezier bezier
;
1755 bezier_init(&bezier
, ox
, oy
,
1756 coords
[0], coords
[1],
1757 coords
[2], coords
[3],
1758 coords
[4], coords
[5]);
1759 bezier_exact_bounds(&bezier
, element_bounds
);
1760 set_bounds(bounds
, element_bounds
, &bounds_inited
);
1766 case VG_LCWARC_TO
: {
1768 struct matrix identity
;
1769 struct path
*path
= path_create(VG_PATH_DATATYPE_F
,
1770 1, 0, 0, 0, VG_PATH_CAPABILITY_ALL
);
1772 matrix_load_identity(&identity
);
1773 arc_init(&arc
, segment
,
1774 ox
, oy
, coords
[3], coords
[4],
1775 coords
[0], coords
[1], coords
[2]);
1777 arc_to_path(&arc
, path
, &identity
);
1779 path_bounding_rect(path
, element_bounds
+ 0, element_bounds
+ 1,
1780 element_bounds
+ 2, element_bounds
+ 3);
1781 set_bounds(bounds
, element_bounds
, &bounds_inited
);
1795 float path_length(struct path
*p
, int start_segment
, int num_segments
)
1799 struct path_iter_data iter
;
1803 VGboolean in_range
= VG_FALSE
;
1805 memset(&iter
, 0, sizeof(struct path_iter_data
));
1808 iter
.coords
= p
->control_points
->data
;
1810 for (i
= 0; i
< (start_segment
+ num_segments
); ++i
) {
1813 iter
.segment
= ((VGubyte
*)(p
->segments
->data
))[i
];
1818 segment
= normalize_coords(&iter
, &num_coords
, coords
);
1820 in_range
= (i
>= start_segment
) && i
<= (start_segment
+ num_segments
);
1825 case VG_MOVE_TO_ABS
:
1827 case VG_CLOSE_PATH
: {
1828 VGfloat line
[4] = {ox
, oy
, iter
.sx
, iter
.sy
};
1829 length
+= line_lengthv(line
);
1832 case VG_LINE_TO_ABS
: {
1833 VGfloat line
[4] = {ox
, oy
, coords
[0], coords
[1]};
1834 length
+= line_lengthv(line
);
1837 case VG_CUBIC_TO_ABS
: {
1838 struct bezier bezier
;
1839 bezier_init(&bezier
, ox
, oy
,
1840 coords
[0], coords
[1],
1841 coords
[2], coords
[3],
1842 coords
[4], coords
[5]);
1843 length
+= bezier_length(&bezier
, BEZIER_DEFAULT_ERROR
);
1849 case VG_LCWARC_TO
: {
1851 struct matrix identity
;
1852 struct path
*path
= path_create(VG_PATH_DATATYPE_F
,
1853 1, 0, 0, 0, VG_PATH_CAPABILITY_ALL
);
1855 matrix_load_identity(&identity
);
1856 arc_init(&arc
, segment
,
1857 ox
, oy
, coords
[3], coords
[4],
1858 coords
[0], coords
[1], coords
[2]);
1860 arc_to_path(&arc
, path
, &identity
);
1862 length
+= path_length(path
, 0, path_num_segments(path
));
1873 static INLINE VGboolean
point_on_current_segment(VGfloat distance
,
1875 VGfloat segment_length
)
1878 (((floatIsZero(distance
) || distance
< 0) && floatIsZero(length
)) ||
1879 ((distance
> length
|| floatsEqual(distance
, length
)) &&
1880 (floatsEqual(distance
, length
+ segment_length
) ||
1881 distance
< (length
+ segment_length
))));
1884 static VGboolean
path_point_segment(struct path_iter_data iter
,
1885 struct path_iter_data prev_iter
,
1888 VGfloat length
, VGfloat
*current_length
,
1889 VGfloat
*point
, VGfloat
*normal
)
1891 switch (iter
.segment
) {
1892 case VG_MOVE_TO_ABS
:
1894 case VG_CLOSE_PATH
: {
1895 VGfloat line
[4] = {prev_iter
.ox
, prev_iter
.oy
, iter
.sx
, iter
.sy
};
1896 VGboolean on_current_segment
= VG_FALSE
;
1897 *current_length
= line_lengthv(line
);
1898 on_current_segment
= point_on_current_segment(distance
,
1901 if (on_current_segment
) {
1902 VGfloat at
= (distance
- length
) / line_lengthv(line
);
1903 line_normal_vector(line
, normal
);
1904 line_point_at(line
, at
, point
);
1909 case VG_LINE_TO_ABS
: {
1910 VGfloat line
[4] = {prev_iter
.ox
, prev_iter
.oy
, coords
[0], coords
[1]};
1911 VGboolean on_current_segment
= VG_FALSE
;
1912 *current_length
= line_lengthv(line
);
1913 on_current_segment
= point_on_current_segment(distance
,
1916 if (on_current_segment
) {
1917 VGfloat at
= (distance
- length
) / line_lengthv(line
);
1918 line_normal_vector(line
, normal
);
1919 line_point_at(line
, at
, point
);
1924 case VG_CUBIC_TO_ABS
: {
1925 struct bezier bezier
;
1926 bezier_init(&bezier
, prev_iter
.ox
, prev_iter
.oy
,
1927 coords
[0], coords
[1],
1928 coords
[2], coords
[3],
1929 coords
[4], coords
[5]);
1930 *current_length
= bezier_length(&bezier
, BEZIER_DEFAULT_ERROR
);
1931 if (point_on_current_segment(distance
, length
, *current_length
)) {
1932 bezier_point_at_length(&bezier
, distance
- length
,
1941 case VG_LCWARC_TO
: {
1943 struct matrix identity
;
1944 struct path
*path
= path_create(VG_PATH_DATATYPE_F
,
1945 1, 0, 0, 0, VG_PATH_CAPABILITY_ALL
);
1947 matrix_load_identity(&identity
);
1948 arc_init(&arc
, iter
.segment
,
1949 prev_iter
.ox
, prev_iter
.oy
, coords
[3], coords
[4],
1950 coords
[0], coords
[1], coords
[2]);
1952 arc_to_path(&arc
, path
, &identity
);
1954 *current_length
= path_length(path
, 0, path_num_segments(path
));
1955 if (point_on_current_segment(distance
, length
, *current_length
)) {
1956 path_point(path
, 0, path_num_segments(path
),
1957 distance
- length
, point
, normal
);
1968 void path_point(struct path
*p
, VGint start_segment
, VGint num_segments
,
1969 VGfloat distance
, VGfloat
*point
, VGfloat
*normal
)
1973 struct path_iter_data iter
, prev_iter
;
1976 VGfloat current_length
= 0;
1978 memset(&iter
, 0, sizeof(struct path_iter_data
));
1979 memset(&prev_iter
, 0, sizeof(struct path_iter_data
));
1988 iter
.coords
= p
->control_points
->data
;
1992 for (i
= 0; i
< (start_segment
+ num_segments
); ++i
) {
1993 VGboolean outside_range
= (i
< start_segment
||
1994 i
>= (start_segment
+ num_segments
));
1998 iter
.segment
= ((VGubyte
*)(p
->segments
->data
))[i
];
1999 iter
.segment
= normalize_coords(&iter
, &num_coords
, coords
);
2004 if (path_point_segment(iter
, prev_iter
, coords
,
2005 distance
, length
, ¤t_length
,
2009 length
+= current_length
;
2013 *OpenVG 1.0 - 8.6.11 vgPointAlongPath
2015 * If distance is greater than or equal to the path length
2016 *(i.e., the value returned by vgPathLength when called with the same
2017 *startSegment and numSegments parameters), the visual ending point of
2021 switch (iter
.segment
) {
2022 case VG_MOVE_TO_ABS
:
2024 case VG_CLOSE_PATH
: {
2025 VGfloat line
[4] = {prev_iter
.ox
, prev_iter
.oy
, iter
.sx
, iter
.sy
};
2026 line_normal_vector(line
, normal
);
2027 line_point_at(line
, 1.f
, point
);
2030 case VG_LINE_TO_ABS
: {
2031 VGfloat line
[4] = {prev_iter
.ox
, prev_iter
.oy
, coords
[0], coords
[1]};
2032 line_normal_vector(line
, normal
);
2033 line_point_at(line
, 1.f
, point
);
2036 case VG_CUBIC_TO_ABS
: {
2037 struct bezier bezier
;
2038 bezier_init(&bezier
, prev_iter
.ox
, prev_iter
.oy
,
2039 coords
[0], coords
[1],
2040 coords
[2], coords
[3],
2041 coords
[4], coords
[5]);
2042 bezier_point_at_t(&bezier
, 1.f
, point
, normal
);
2048 case VG_LCWARC_TO
: {
2050 struct matrix identity
;
2051 struct path
*path
= path_create(VG_PATH_DATATYPE_F
,
2052 1, 0, 0, 0, VG_PATH_CAPABILITY_ALL
);
2054 matrix_load_identity(&identity
);
2055 arc_init(&arc
, iter
.segment
,
2056 prev_iter
.ox
, prev_iter
.oy
, coords
[3], coords
[4],
2057 coords
[0], coords
[1], coords
[2]);
2059 arc_to_path(&arc
, path
, &identity
);
2061 path_point(path
, 0, path_num_segments(path
),
2062 /* to make sure we're bigger than len * 2 it */
2063 2 * path_length(path
, 0, path_num_segments(path
)),
2073 VGboolean
path_is_empty(struct path
*p
)
2075 return p
->segments
->num_elements
== 0;