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 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(), VG_OBJECT_PATH
, p
);
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
);
240 VGbitfield
path_capabilities(struct path
*p
)
245 void path_set_capabilities(struct path
*p
, VGbitfield bf
)
247 p
->caps
= (bf
& VG_PATH_CAPABILITY_ALL
);
250 void path_append_data(struct path
*p
,
252 const VGubyte
* pathSegments
,
253 const void * pathData
)
255 VGint old_segments
= p
->num_segments
;
256 VGint num_new_coords
= num_elements_for_segments(pathSegments
, numSegments
);
257 array_append_data(p
->segments
, pathSegments
, numSegments
);
258 array_append_data(p
->control_points
, pathData
, num_new_coords
);
260 p
->num_segments
+= numSegments
;
261 if (!floatsEqual(p
->scale
, 1.f
) || !floatsEqual(p
->bias
, 0.f
)) {
262 VGubyte
*coords
= (VGubyte
*)p
->control_points
->data
;
263 coords_adjust_by_scale_bias(p
,
264 coords
+ old_segments
* p
->control_points
->datatype_size
,
266 p
->scale
, p
->bias
, p
->datatype
);
269 p
->dirty_stroke
= VG_TRUE
;
272 VGint
path_num_segments(struct path
*p
)
274 return p
->num_segments
;
277 static INLINE
void map_if_relative(VGfloat ox
, VGfloat oy
,
279 VGfloat
*x
, VGfloat
*y
)
289 static INLINE
void close_polygon(struct polygon
*current
,
290 VGfloat sx
, VGfloat sy
,
291 VGfloat ox
, VGfloat oy
,
292 struct matrix
*matrix
)
294 if (!floatsEqual(sx
, ox
) ||
295 !floatsEqual(sy
, oy
)) {
298 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
299 polygon_vertex_append(current
, x0
, y0
);
303 static void convert_path(struct path
*p
,
309 void *coords
= (VGfloat
*)p
->control_points
->data
;
310 VGubyte
*common_data
= (VGubyte
*)dst
;
311 VGint size_dst
= size_for_datatype(to
);
314 for (i
= 0; i
< num_coords
; ++i
) {
315 data_at(&coords
, p
, 0, 1, data
);
316 vg_float_to_datatype(to
, common_data
, data
, 1);
317 common_data
+= size_dst
;
321 static void polygon_array_calculate_bounds( struct polygon_array
*polyarray
)
323 struct array
*polys
= polyarray
->array
;
324 VGfloat min_x
, max_x
;
325 VGfloat min_y
, max_y
;
331 if (!polys
->num_elements
) {
332 polyarray
->min_x
= 0.0f
;
333 polyarray
->min_y
= 0.0f
;
334 polyarray
->max_x
= 0.0f
;
335 polyarray
->max_y
= 0.0f
;
339 polygon_bounding_rect((((struct polygon
**)polys
->data
)[0]), bounds
);
342 max_x
= bounds
[0] + bounds
[2];
343 max_y
= bounds
[1] + bounds
[3];
344 for (i
= 1; i
< polys
->num_elements
; ++i
) {
345 struct polygon
*p
= (((struct polygon
**)polys
->data
)[i
]);
346 polygon_bounding_rect(p
, bounds
);
347 min_x
= MIN2(min_x
, bounds
[0]);
348 min_y
= MIN2(min_y
, bounds
[1]);
349 max_x
= MAX2(max_x
, bounds
[0] + bounds
[2]);
350 max_y
= MAX2(max_y
, bounds
[1] + bounds
[3]);
353 polyarray
->min_x
= min_x
;
354 polyarray
->min_y
= min_y
;
355 polyarray
->max_x
= max_x
;
356 polyarray
->max_y
= max_y
;
360 static struct polygon_array
* path_get_fill_polygons(struct path
*p
, struct matrix
*matrix
)
363 struct polygon
*current
= 0;
364 VGfloat sx
, sy
, px
, py
, ox
, oy
;
365 VGfloat x0
, y0
, x1
, y1
, x2
, y2
, x3
, y3
;
366 VGfloat data
[8] = {};
367 void *coords
= (VGfloat
*)p
->control_points
->data
;
370 if (p
->fill_polys
.polygon_array
.array
)
372 if (memcmp( &p
->fill_polys
.matrix
,
374 sizeof *matrix
) == 0 && p
->dirty
== VG_FALSE
)
376 return &p
->fill_polys
.polygon_array
;
379 polygon_array_cleanup(&p
->fill_polys
.polygon_array
);
383 /* an array of pointers to polygons */
384 array
= array_create(sizeof(struct polygon
*));
386 sx
= sy
= px
= py
= ox
= oy
= 0.f
;
389 current
= polygon_create(32);
391 for (i
= 0; i
< p
->num_segments
; ++i
) {
392 VGubyte segment
= ((VGubyte
*)(p
->segments
->data
))[i
];
393 VGint command
= SEGMENT_COMMAND(segment
);
394 VGboolean relative
= SEGMENT_ABS_REL(segment
);
398 close_polygon(current
, sx
, sy
, ox
, oy
, matrix
);
403 if (current
&& polygon_vertex_count(current
) > 0) {
405 close_polygon(current
, sx
, sy
, ox
, oy
, matrix
);
406 array_append_data(array
, ¤t
, 1);
407 current
= polygon_create(32);
409 data_at(&coords
, p
, 0, 2, data
);
412 map_if_relative(ox
, oy
, relative
, &x0
, &y0
);
419 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
420 polygon_vertex_append(current
, x0
, y0
);
423 data_at(&coords
, p
, 0, 2, data
);
426 map_if_relative(ox
, oy
, relative
, &x0
, &y0
);
431 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
432 polygon_vertex_append(current
, x0
, y0
);
435 data_at(&coords
, p
, 0, 1, data
);
438 map_if_relative(ox
, oy
, relative
, &x0
, 0);
442 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
443 polygon_vertex_append(current
, x0
, y0
);
446 data_at(&coords
, p
, 0, 1, data
);
449 map_if_relative(ox
, oy
, relative
, 0, &y0
);
453 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
454 polygon_vertex_append(current
, x0
, y0
);
457 struct bezier bezier
;
458 data_at(&coords
, p
, 0, 6, data
);
467 map_if_relative(ox
, oy
, relative
, &x1
, &y1
);
468 map_if_relative(ox
, oy
, relative
, &x2
, &y2
);
469 map_if_relative(ox
, oy
, relative
, &x3
, &y3
);
474 assert(matrix_is_affine(matrix
));
475 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
476 matrix_map_point(matrix
, x1
, y1
, &x1
, &y1
);
477 matrix_map_point(matrix
, x2
, y2
, &x2
, &y2
);
478 matrix_map_point(matrix
, x3
, y3
, &x3
, &y3
);
479 bezier_init(&bezier
, x0
, y0
, x1
, y1
,
481 bezier_add_to_polygon(&bezier
, current
);
485 struct bezier bezier
;
486 data_at(&coords
, p
, 0, 4, data
);
493 map_if_relative(ox
, oy
, relative
, &x1
, &y1
);
494 map_if_relative(ox
, oy
, relative
, &x3
, &y3
);
497 { /* form a cubic out of it */
498 x2
= (x3
+ 2*x1
) / 3.f
;
499 y2
= (y3
+ 2*y1
) / 3.f
;
500 x1
= (x0
+ 2*x1
) / 3.f
;
501 y1
= (y0
+ 2*y1
) / 3.f
;
505 assert(matrix_is_affine(matrix
));
506 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
507 matrix_map_point(matrix
, x1
, y1
, &x1
, &y1
);
508 matrix_map_point(matrix
, x2
, y2
, &x2
, &y2
);
509 matrix_map_point(matrix
, x3
, y3
, &x3
, &y3
);
510 bezier_init(&bezier
, x0
, y0
, x1
, y1
,
512 bezier_add_to_polygon(&bezier
, current
);
516 struct bezier bezier
;
517 data_at(&coords
, p
, 0, 2, data
);
524 map_if_relative(ox
, oy
, relative
, &x3
, &y3
);
527 { /* form a cubic out of it */
528 x2
= (x3
+ 2*x1
) / 3.f
;
529 y2
= (y3
+ 2*y1
) / 3.f
;
530 x1
= (x0
+ 2*x1
) / 3.f
;
531 y1
= (y0
+ 2*y1
) / 3.f
;
535 assert(matrix_is_affine(matrix
));
536 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
537 matrix_map_point(matrix
, x1
, y1
, &x1
, &y1
);
538 matrix_map_point(matrix
, x2
, y2
, &x2
, &y2
);
539 matrix_map_point(matrix
, x3
, y3
, &x3
, &y3
);
540 bezier_init(&bezier
, x0
, y0
, x1
, y1
,
542 bezier_add_to_polygon(&bezier
, current
);
546 struct bezier bezier
;
547 data_at(&coords
, p
, 0, 4, data
);
556 map_if_relative(ox
, oy
, relative
, &x2
, &y2
);
557 map_if_relative(ox
, oy
, relative
, &x3
, &y3
);
562 assert(matrix_is_affine(matrix
));
563 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
564 matrix_map_point(matrix
, x1
, y1
, &x1
, &y1
);
565 matrix_map_point(matrix
, x2
, y2
, &x2
, &y2
);
566 matrix_map_point(matrix
, x3
, y3
, &x3
, &y3
);
567 bezier_init(&bezier
, x0
, y0
, x1
, y1
,
569 bezier_add_to_polygon(&bezier
, current
);
579 data_at(&coords
, p
, 0, 5, data
);
587 map_if_relative(ox
, oy
, relative
, &x1
, &y1
);
589 debug_printf("------- ARC (%f, %f), (%f, %f) %f, %f, %f\n",
590 x0
, y0
, x1
, y1
, rh
, rv
, rot
);
592 arc_init(&arc
, command
, x0
, y0
, x1
, y1
,
594 arc_add_to_polygon(&arc
, current
,
604 assert(!"Unknown segment!");
608 if (polygon_vertex_count(current
) > 0) {
609 close_polygon(current
, sx
, sy
, ox
, oy
, matrix
);
610 array_append_data(array
, ¤t
, 1);
612 polygon_destroy(current
);
615 p
->fill_polys
.polygon_array
.array
= array
;
616 p
->fill_polys
.matrix
= *matrix
;
618 polygon_array_calculate_bounds( &p
->fill_polys
.polygon_array
);
622 return &p
->fill_polys
.polygon_array
;
625 VGbyte
path_datatype_size(struct path
*p
)
627 return size_for_datatype(p
->datatype
);
630 VGPathDatatype
path_datatype(struct path
*p
)
635 VGfloat
path_scale(struct path
*p
)
640 VGfloat
path_bias(struct path
*p
)
645 VGint
path_num_coords(struct path
*p
)
647 return num_elements_for_segments((VGubyte
*)p
->segments
->data
,
651 void path_modify_coords(struct path
*p
,
654 const void * pathData
)
656 VGubyte
*segments
= (VGubyte
*)(p
->segments
->data
);
657 VGint count
= num_elements_for_segments(&segments
[startIndex
], numSegments
);
658 VGint start_cp
= num_elements_for_segments(segments
, startIndex
);
660 array_change_data(p
->control_points
, pathData
, start_cp
, count
);
661 coords_adjust_by_scale_bias(p
,
662 ((VGubyte
*)p
->control_points
->data
) +
663 (startIndex
* p
->control_points
->datatype_size
),
665 p
->scale
, p
->bias
, p
->datatype
);
667 p
->dirty_stroke
= VG_TRUE
;
670 void path_for_each_segment(struct path
*path
,
675 struct path_for_each_data p
;
677 void *coords
= (VGfloat
*)path
->control_points
->data
;
680 p
.sx
= p
.sy
= p
.px
= p
.py
= p
.ox
= p
.oy
= 0.f
;
681 p
.user_data
= user_data
;
683 for (i
= 0; i
< path
->num_segments
; ++i
) {
687 p
.segment
= ((VGubyte
*)(path
->segments
->data
))[i
];
688 command
= SEGMENT_COMMAND(p
.segment
);
689 relative
= SEGMENT_ABS_REL(p
.segment
);
696 data_at(&coords
, path
, 0, 2, data
);
697 map_if_relative(p
.ox
, p
.oy
, relative
, &data
[0], &data
[1]);
707 data_at(&coords
, path
, 0, 2, data
);
708 map_if_relative(p
.ox
, p
.oy
, relative
, &data
[0], &data
[1]);
716 data_at(&coords
, path
, 0, 1, data
);
717 map_if_relative(p
.ox
, p
.oy
, relative
, &data
[0], 0);
718 p
.segment
= VG_LINE_TO
;
727 data_at(&coords
, path
, 0, 1, data
);
728 map_if_relative(p
.ox
, p
.oy
, relative
, 0, &data
[0]);
729 p
.segment
= VG_LINE_TO
;
739 data_at(&coords
, path
, 0, 6, data
);
740 map_if_relative(p
.ox
, p
.oy
, relative
, &data
[0], &data
[1]);
741 map_if_relative(p
.ox
, p
.oy
, relative
, &data
[2], &data
[3]);
742 map_if_relative(p
.ox
, p
.oy
, relative
, &data
[4], &data
[5]);
751 data_at(&coords
, path
, 0, 4, data
);
752 map_if_relative(p
.ox
, p
.oy
, relative
, &data
[0], &data
[1]);
753 map_if_relative(p
.ox
, p
.oy
, relative
, &data
[2], &data
[3]);
762 data_at(&coords
, path
, 0, 2, data
);
763 map_if_relative(p
.ox
, p
.oy
, relative
, &data
[0], &data
[1]);
772 data_at(&coords
, path
, 0, 4, data
);
773 map_if_relative(p
.ox
, p
.oy
, relative
, &data
[0], &data
[1]);
774 map_if_relative(p
.ox
, p
.oy
, relative
, &data
[2], &data
[3]);
786 data_at(&coords
, path
, 0, 5, data
);
787 map_if_relative(p
.ox
, p
.oy
, relative
, &data
[3], &data
[4]);
789 debug_printf("------- ARC (%f, %f), (%f, %f) %f, %f, %f\n",
790 p
.ox
, p
.oy
, data
[3], data
[4], data
[0], data
[1], data
[2]);
801 assert(!"Unknown segment!");
806 struct transform_data
{
807 struct array
*segments
;
808 struct array
*coords
;
810 struct matrix
*matrix
;
812 VGPathDatatype datatype
;
815 static VGboolean
transform_cb(struct path
*p
,
816 struct path_for_each_data
*pd
)
818 struct transform_data
*td
= (struct transform_data
*)pd
->user_data
;
819 VGint num_coords
= num_elements_for_segments(&pd
->segment
, 1);
820 VGubyte segment
= SEGMENT_COMMAND(pd
->segment
);/* abs bit is 0 */
822 VGubyte common_data
[sizeof(VGfloat
)*8];
824 memcpy(data
, pd
->coords
, sizeof(VGfloat
) * num_coords
);
830 matrix_map_point(td
->matrix
,
831 data
[0], data
[1], &data
[0], &data
[1]);
834 matrix_map_point(td
->matrix
,
835 data
[0], data
[1], &data
[0], &data
[1]);
842 matrix_map_point(td
->matrix
,
843 data
[0], data
[1], &data
[0], &data
[1]);
844 matrix_map_point(td
->matrix
,
845 data
[2], data
[3], &data
[2], &data
[3]);
848 matrix_map_point(td
->matrix
,
849 data
[0], data
[1], &data
[0], &data
[1]);
850 matrix_map_point(td
->matrix
,
851 data
[2], data
[3], &data
[2], &data
[3]);
852 matrix_map_point(td
->matrix
,
853 data
[4], data
[5], &data
[4], &data
[5]);
856 matrix_map_point(td
->matrix
,
857 data
[0], data
[1], &data
[0], &data
[1]);
860 matrix_map_point(td
->matrix
,
861 data
[0], data
[1], &data
[0], &data
[1]);
862 matrix_map_point(td
->matrix
,
863 data
[2], data
[3], &data
[2], &data
[3]);
870 struct path
*path
= path_create(td
->datatype
,
871 1, 0, 0, 0, VG_PATH_CAPABILITY_ALL
);
872 arc_init(&arc
, segment
,
873 pd
->ox
, pd
->oy
, data
[3], data
[4],
874 data
[0], data
[1], data
[2]);
876 arc_to_path(&arc
, path
, td
->matrix
);
878 num_coords
= path_num_coords(path
);
880 array_append_data(td
->segments
, path
->segments
->data
,
882 array_append_data(td
->coords
, path
->control_points
->data
,
893 vg_float_to_datatype(td
->datatype
, common_data
, data
, num_coords
);
895 array_append_data(td
->segments
, &pd
->segment
, 1);
896 array_append_data(td
->coords
, common_data
, num_coords
);
900 void path_transform(struct path
*dst
, struct path
*src
)
902 struct transform_data data
;
903 struct vg_context
*ctx
= dst
->base
.ctx
;
905 data
.segments
= dst
->segments
;
906 data
.coords
= dst
->control_points
;
907 data
.matrix
= &ctx
->state
.vg
.path_user_to_surface_matrix
;
908 data
.datatype
= dst
->datatype
;
910 path_for_each_segment(src
, transform_cb
, (void*)&data
);
912 dst
->num_segments
= dst
->segments
->num_elements
;
913 dst
->dirty
= VG_TRUE
;
914 dst
->dirty_stroke
= VG_TRUE
;
917 void path_append_path(struct path
*dst
,
920 VGint num_coords
= path_num_coords(src
);
921 void *dst_data
= malloc(size_for_datatype(dst
->datatype
) * num_coords
);
922 array_append_data(dst
->segments
,
925 convert_path(src
, dst
->datatype
,
926 dst_data
, num_coords
);
927 array_append_data(dst
->control_points
,
932 dst
->num_segments
+= src
->num_segments
;
933 dst
->dirty
= VG_TRUE
;
934 dst
->dirty_stroke
= VG_TRUE
;
937 static INLINE VGboolean
is_segment_arc(VGubyte segment
)
939 VGubyte scommand
= SEGMENT_COMMAND(segment
);
940 return (scommand
== VG_SCCWARC_TO
||
941 scommand
== VG_SCWARC_TO
||
942 scommand
== VG_LCCWARC_TO
||
943 scommand
== VG_LCWARC_TO
);
946 struct path_iter_data
{
950 VGfloat px
, py
, ox
, oy
, sx
, sy
;
952 static INLINE VGubyte
normalize_coords(struct path_iter_data
*pd
,
956 VGint command
= SEGMENT_COMMAND(pd
->segment
);
957 VGboolean relative
= SEGMENT_ABS_REL(pd
->segment
);
964 return VG_CLOSE_PATH
;
967 data_at(&pd
->coords
, pd
->path
, 0, 2, data
);
968 map_if_relative(pd
->ox
, pd
->oy
, relative
, &data
[0], &data
[1]);
976 return VG_MOVE_TO_ABS
;
979 data_at(&pd
->coords
, pd
->path
, 0, 2, data
);
980 map_if_relative(pd
->ox
, pd
->oy
, relative
, &data
[0], &data
[1]);
986 return VG_LINE_TO_ABS
;
989 data_at(&pd
->coords
, pd
->path
, 0, 1, data
);
990 map_if_relative(pd
->ox
, pd
->oy
, relative
, &data
[0], 0);
997 return VG_LINE_TO_ABS
;
1000 data_at(&pd
->coords
, pd
->path
, 0, 1, data
);
1001 map_if_relative(pd
->ox
, pd
->oy
, relative
, 0, &data
[0]);
1009 return VG_LINE_TO_ABS
;
1012 data_at(&pd
->coords
, pd
->path
, 0, 6, data
);
1013 map_if_relative(pd
->ox
, pd
->oy
, relative
, &data
[0], &data
[1]);
1014 map_if_relative(pd
->ox
, pd
->oy
, relative
, &data
[2], &data
[3]);
1015 map_if_relative(pd
->ox
, pd
->oy
, relative
, &data
[4], &data
[5]);
1021 return VG_CUBIC_TO_ABS
;
1025 VGfloat x0
, y0
, x1
, y1
, x2
, y2
, x3
, y3
;
1026 data_at(&pd
->coords
, pd
->path
, 0, 4, data
);
1033 map_if_relative(pd
->ox
, pd
->oy
, relative
, &x1
, &y1
);
1034 map_if_relative(pd
->ox
, pd
->oy
, relative
, &x3
, &y3
);
1037 { /* form a cubic out of it */
1038 x2
= (x3
+ 2*x1
) / 3.f
;
1039 y2
= (y3
+ 2*y1
) / 3.f
;
1040 x1
= (x0
+ 2*x1
) / 3.f
;
1041 y1
= (y0
+ 2*y1
) / 3.f
;
1052 return VG_CUBIC_TO_ABS
;
1056 VGfloat x0
, y0
, x1
, y1
, x2
, y2
, x3
, y3
;
1057 data_at(&pd
->coords
, pd
->path
, 0, 2, data
);
1060 x1
= 2 * pd
->ox
- pd
->px
;
1061 y1
= 2 * pd
->oy
- pd
->py
;
1064 map_if_relative(pd
->ox
, pd
->oy
, relative
, &x3
, &y3
);
1067 { /* form a cubic out of it */
1068 x2
= (x3
+ 2*x1
) / 3.f
;
1069 y2
= (y3
+ 2*y1
) / 3.f
;
1070 x1
= (x0
+ 2*x1
) / 3.f
;
1071 y1
= (y0
+ 2*y1
) / 3.f
;
1082 return VG_CUBIC_TO_ABS
;
1085 case VG_SCUBIC_TO
: {
1086 VGfloat x0
, y0
, x1
, y1
, x2
, y2
, x3
, y3
;
1087 data_at(&pd
->coords
, pd
->path
, 0, 4, data
);
1090 x1
= 2*pd
->ox
-pd
->px
;
1091 y1
= 2*pd
->oy
-pd
->py
;
1096 map_if_relative(x0
, y0
, relative
, &x2
, &y2
);
1097 map_if_relative(x0
, y0
, relative
, &x3
, &y3
);
1109 return VG_CUBIC_TO_ABS
;
1115 case VG_LCWARC_TO
: {
1116 data_at(&pd
->coords
, pd
->path
, 0, 5, data
);
1117 map_if_relative(pd
->ox
, pd
->oy
, relative
, &data
[3], &data
[4]);
1123 return command
| VG_ABSOLUTE
;
1128 assert(!"Unknown segment!");
1132 static void linearly_interpolate(VGfloat
*result
,
1133 const VGfloat
*start
,
1139 for (i
= 0; i
< number
; ++i
) {
1140 result
[i
] = start
[i
] + (end
[i
] - start
[i
]) * amount
;
1144 VGboolean
path_interpolate(struct path
*dst
,
1145 struct path
*start
, struct path
*end
,
1148 /* temporary path that we can discard if it will turn
1149 * out that start is not compatible with end */
1150 struct path
*res_path
= path_create(dst
->datatype
,
1154 VGfloat start_coords
[8];
1155 VGfloat end_coords
[8];
1157 VGubyte common_data
[sizeof(VGfloat
)*8];
1158 struct path_iter_data start_iter
, end_iter
;
1160 memset(&start_iter
, 0, sizeof(struct path_iter_data
));
1161 memset(&end_iter
, 0, sizeof(struct path_iter_data
));
1163 start_iter
.path
= start
;
1164 start_iter
.coords
= start
->control_points
->data
;
1165 end_iter
.path
= end
;
1166 end_iter
.coords
= end
->control_points
->data
;
1168 for (i
= 0; i
< start
->num_segments
; ++i
) {
1170 VGubyte ssegment
, esegment
;
1171 VGint snum_coords
, enum_coords
;
1172 start_iter
.segment
= ((VGubyte
*)(start
->segments
->data
))[i
];
1173 end_iter
.segment
= ((VGubyte
*)(end
->segments
->data
))[i
];
1175 ssegment
= normalize_coords(&start_iter
, &snum_coords
,
1177 esegment
= normalize_coords(&end_iter
, &enum_coords
,
1180 if (is_segment_arc(ssegment
)) {
1181 if (!is_segment_arc(esegment
)) {
1182 path_destroy(res_path
);
1189 } else if (is_segment_arc(esegment
)) {
1190 path_destroy(res_path
);
1193 else if (ssegment
!= esegment
) {
1194 path_destroy(res_path
);
1200 linearly_interpolate(results
, start_coords
, end_coords
,
1201 amount
, snum_coords
);
1202 vg_float_to_datatype(dst
->datatype
, common_data
, results
, snum_coords
);
1203 path_append_data(res_path
, 1, &segment
, common_data
);
1206 path_append_path(dst
, res_path
);
1207 path_destroy(res_path
);
1209 dst
->dirty
= VG_TRUE
;
1210 dst
->dirty_stroke
= VG_TRUE
;
1215 void path_clear(struct path
*p
, VGbitfield capabilities
)
1217 path_set_capabilities(p
, capabilities
);
1218 array_destroy(p
->segments
);
1219 array_destroy(p
->control_points
);
1220 p
->segments
= array_create(size_for_datatype(VG_PATH_DATATYPE_S_8
));
1221 p
->control_points
= array_create(size_for_datatype(p
->datatype
));
1222 p
->num_segments
= 0;
1224 p
->dirty_stroke
= VG_TRUE
;
1227 struct path
* path_create_stroke(struct path
*p
,
1228 struct matrix
*matrix
)
1231 VGfloat sx
, sy
, px
, py
, ox
, oy
;
1232 VGfloat x0
, y0
, x1
, y1
, x2
, y2
, x3
, y3
;
1233 VGfloat data
[8] = {};
1234 void *coords
= (VGfloat
*)p
->control_points
->data
;
1235 int dashed
= (p
->base
.ctx
->state
.vg
.stroke
.dash_pattern_num
? 1 : 0);
1236 struct dash_stroker stroker
;
1237 struct vg_state
*vg_state
= &p
->base
.ctx
->state
.vg
;
1239 if (p
->stroked
.path
)
1241 /* ### compare the dash patterns to see if we can cache them.
1242 * for now we simply always bail out if the path is dashed.
1244 if (memcmp( &p
->stroked
.matrix
,
1246 sizeof *matrix
) == 0 &&
1247 !dashed
&& !p
->dirty_stroke
&&
1248 floatsEqual(p
->stroked
.stroke_width
, vg_state
->stroke
.line_width
.f
) &&
1249 floatsEqual(p
->stroked
.miter_limit
, vg_state
->stroke
.miter_limit
.f
) &&
1250 p
->stroked
.cap_style
== vg_state
->stroke
.cap_style
&&
1251 p
->stroked
.join_style
== vg_state
->stroke
.join_style
)
1253 return p
->stroked
.path
;
1256 path_destroy( p
->stroked
.path
);
1257 p
->stroked
.path
= NULL
;
1262 sx
= sy
= px
= py
= ox
= oy
= 0.f
;
1265 dash_stroker_init((struct stroker
*)&stroker
, vg_state
);
1267 stroker_init((struct stroker
*)&stroker
, vg_state
);
1269 stroker_begin((struct stroker
*)&stroker
);
1271 for (i
= 0; i
< p
->num_segments
; ++i
) {
1272 VGubyte segment
= ((VGubyte
*)(p
->segments
->data
))[i
];
1273 VGint command
= SEGMENT_COMMAND(segment
);
1274 VGboolean relative
= SEGMENT_ABS_REL(segment
);
1277 case VG_CLOSE_PATH
: {
1280 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
1281 stroker_line_to((struct stroker
*)&stroker
, x0
, y0
);
1285 data_at(&coords
, p
, 0, 2, data
);
1288 map_if_relative(ox
, oy
, relative
, &x0
, &y0
);
1295 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
1296 stroker_move_to((struct stroker
*)&stroker
, x0
, y0
);
1299 data_at(&coords
, p
, 0, 2, data
);
1302 map_if_relative(ox
, oy
, relative
, &x0
, &y0
);
1307 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
1308 stroker_line_to((struct stroker
*)&stroker
, x0
, y0
);
1311 data_at(&coords
, p
, 0, 1, data
);
1314 map_if_relative(ox
, oy
, relative
, &x0
, 0);
1318 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
1319 stroker_line_to((struct stroker
*)&stroker
, x0
, y0
);
1322 data_at(&coords
, p
, 0, 1, data
);
1325 map_if_relative(ox
, oy
, relative
, 0, &y0
);
1329 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
1330 stroker_line_to((struct stroker
*)&stroker
, x0
, y0
);
1333 data_at(&coords
, p
, 0, 6, data
);
1342 map_if_relative(ox
, oy
, relative
, &x1
, &y1
);
1343 map_if_relative(ox
, oy
, relative
, &x2
, &y2
);
1344 map_if_relative(ox
, oy
, relative
, &x3
, &y3
);
1345 if (floatsEqual(x1
, ox
) && floatsEqual(y1
, oy
) &&
1346 floatsEqual(x1
, x2
) && floatsEqual(y1
, y2
) &&
1347 floatsEqual(x2
, x3
) && floatsEqual(y2
, y3
)) {
1348 /*ignore the empty segment */
1350 } else if (floatsEqual(x3
, ox
) && floatsEqual(y3
, oy
)) {
1351 /* if dup vertex, emit a line */
1354 matrix_map_point(matrix
, x3
, y3
, &x3
, &y3
);
1355 stroker_line_to((struct stroker
*)&stroker
, x3
, y3
);
1362 assert(matrix_is_affine(matrix
));
1363 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
1364 matrix_map_point(matrix
, x1
, y1
, &x1
, &y1
);
1365 matrix_map_point(matrix
, x2
, y2
, &x2
, &y2
);
1366 matrix_map_point(matrix
, x3
, y3
, &x3
, &y3
);
1367 stroker_curve_to((struct stroker
*)&stroker
, x1
, y1
, x2
, y2
, x3
, y3
);
1371 data_at(&coords
, p
, 0, 4, data
);
1378 map_if_relative(ox
, oy
, relative
, &x1
, &y1
);
1379 map_if_relative(ox
, oy
, relative
, &x3
, &y3
);
1382 { /* form a cubic out of it */
1383 x2
= (x3
+ 2*x1
) / 3.f
;
1384 y2
= (y3
+ 2*y1
) / 3.f
;
1385 x1
= (x0
+ 2*x1
) / 3.f
;
1386 y1
= (y0
+ 2*y1
) / 3.f
;
1388 if (floatsEqual(x1
, ox
) && floatsEqual(y1
, oy
) &&
1389 floatsEqual(x1
, x2
) && floatsEqual(y1
, y2
) &&
1390 floatsEqual(x2
, x3
) && floatsEqual(y2
, y3
)) {
1391 /*ignore the empty segment */
1393 } else if (floatsEqual(x3
, ox
) && floatsEqual(y3
, oy
)) {
1394 /* if dup vertex, emit a line */
1397 matrix_map_point(matrix
, x3
, y3
, &x3
, &y3
);
1398 stroker_line_to((struct stroker
*)&stroker
, x3
, y3
);
1403 assert(matrix_is_affine(matrix
));
1404 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
1405 matrix_map_point(matrix
, x1
, y1
, &x1
, &y1
);
1406 matrix_map_point(matrix
, x2
, y2
, &x2
, &y2
);
1407 matrix_map_point(matrix
, x3
, y3
, &x3
, &y3
);
1408 stroker_curve_to((struct stroker
*)&stroker
, x1
, y1
, x2
, y2
, x3
, y3
);
1412 data_at(&coords
, p
, 0, 2, data
);
1419 map_if_relative(ox
, oy
, relative
, &x3
, &y3
);
1422 { /* form a cubic out of it */
1423 x2
= (x3
+ 2*x1
) / 3.f
;
1424 y2
= (y3
+ 2*y1
) / 3.f
;
1425 x1
= (x0
+ 2*x1
) / 3.f
;
1426 y1
= (y0
+ 2*y1
) / 3.f
;
1428 if (floatsEqual(x1
, ox
) && floatsEqual(y1
, oy
) &&
1429 floatsEqual(x1
, x2
) && floatsEqual(y1
, y2
) &&
1430 floatsEqual(x2
, x3
) && floatsEqual(y2
, y3
)) {
1431 /*ignore the empty segment */
1433 } else if (floatsEqual(x3
, ox
) && floatsEqual(y3
, oy
)) {
1434 /* if dup vertex, emit a line */
1437 matrix_map_point(matrix
, x3
, y3
, &x3
, &y3
);
1438 stroker_line_to((struct stroker
*)&stroker
, x3
, y3
);
1443 assert(matrix_is_affine(matrix
));
1444 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
1445 matrix_map_point(matrix
, x1
, y1
, &x1
, &y1
);
1446 matrix_map_point(matrix
, x2
, y2
, &x2
, &y2
);
1447 matrix_map_point(matrix
, x3
, y3
, &x3
, &y3
);
1448 stroker_curve_to((struct stroker
*)&stroker
, x1
, y1
, x2
, y2
, x3
, y3
);
1451 case VG_SCUBIC_TO
: {
1452 data_at(&coords
, p
, 0, 4, data
);
1461 map_if_relative(ox
, oy
, relative
, &x2
, &y2
);
1462 map_if_relative(ox
, oy
, relative
, &x3
, &y3
);
1463 if (floatsEqual(x1
, ox
) && floatsEqual(y1
, oy
) &&
1464 floatsEqual(x1
, x2
) && floatsEqual(y1
, y2
) &&
1465 floatsEqual(x2
, x3
) && floatsEqual(y2
, y3
)) {
1466 /*ignore the empty segment */
1468 } else if (floatsEqual(x3
, ox
) && floatsEqual(y3
, oy
)) {
1469 /* if dup vertex, emit a line */
1472 matrix_map_point(matrix
, x3
, y3
, &x3
, &y3
);
1473 stroker_line_to((struct stroker
*)&stroker
, x3
, y3
);
1480 assert(matrix_is_affine(matrix
));
1481 matrix_map_point(matrix
, x0
, y0
, &x0
, &y0
);
1482 matrix_map_point(matrix
, x1
, y1
, &x1
, &y1
);
1483 matrix_map_point(matrix
, x2
, y2
, &x2
, &y2
);
1484 matrix_map_point(matrix
, x3
, y3
, &x3
, &y3
);
1485 stroker_curve_to((struct stroker
*)&stroker
, x1
, y1
, x2
, y2
, x3
, y3
);
1491 case VG_LCWARC_TO
: {
1492 VGfloat rh
, rv
, rot
;
1495 data_at(&coords
, p
, 0, 5, data
);
1503 map_if_relative(ox
, oy
, relative
, &x1
, &y1
);
1504 if (floatsEqual(x1
, ox
) && floatsEqual(y1
, oy
)) {
1505 /* if dup vertex, emit a line */
1508 matrix_map_point(matrix
, x1
, y1
, &x1
, &y1
);
1509 stroker_line_to((struct stroker
*)&stroker
, x1
, y1
);
1512 arc_init(&arc
, command
, x0
, y0
, x1
, y1
,
1514 arc_stroke_cb(&arc
, (struct stroker
*)&stroker
,
1524 assert(!"Unknown segment!");
1528 stroker_end((struct stroker
*)&stroker
);
1531 dash_stroker_cleanup((struct dash_stroker
*)&stroker
);
1533 stroker_cleanup((struct stroker
*)&stroker
);
1535 p
->stroked
.path
= stroker
.base
.path
;
1536 p
->stroked
.matrix
= *matrix
;
1537 p
->dirty_stroke
= VG_FALSE
;
1538 p
->stroked
.stroke_width
= vg_state
->stroke
.line_width
.f
;
1539 p
->stroked
.miter_limit
= vg_state
->stroke
.miter_limit
.f
;
1540 p
->stroked
.cap_style
= vg_state
->stroke
.cap_style
;
1541 p
->stroked
.join_style
= vg_state
->stroke
.join_style
;
1543 return stroker
.base
.path
;
1546 void path_render(struct path
*p
, VGbitfield paintModes
,
1549 struct vg_context
*ctx
= vg_current_context();
1550 struct matrix paint_matrix
;
1552 vg_validate_state(ctx
);
1554 shader_set_drawing_image(ctx
->shader
, VG_FALSE
);
1555 shader_set_image(ctx
->shader
, 0);
1557 fprintf(stderr
, "Matrix(11=%f 12=%f 13=%f 21=%f 22=%f 23=%f 31=%f 32=%f 33=%f)\n",
1558 mat
->m
[0], mat
->m
[1], mat
->m
[2],
1559 mat
->m
[3], mat
->m
[4], mat
->m
[5],
1560 mat
->m
[6], mat
->m
[7], mat
->m
[8]);
1562 if ((paintModes
& VG_FILL_PATH
) &&
1563 vg_get_paint_matrix(ctx
,
1564 &ctx
->state
.vg
.fill_paint_to_user_matrix
,
1567 /* First the fill */
1568 shader_set_surface_matrix(ctx
->shader
, mat
);
1569 shader_set_paint(ctx
->shader
, ctx
->state
.vg
.fill_paint
);
1570 shader_set_paint_matrix(ctx
->shader
, &paint_matrix
);
1571 shader_bind(ctx
->shader
);
1575 if ((paintModes
& VG_STROKE_PATH
) &&
1576 vg_get_paint_matrix(ctx
,
1577 &ctx
->state
.vg
.stroke_paint_to_user_matrix
,
1580 /* 8.7.5: "line width less than or equal to 0 prevents stroking from
1582 if (ctx
->state
.vg
.stroke
.line_width
.f
<= 0)
1584 shader_set_surface_matrix(ctx
->shader
, mat
);
1585 shader_set_paint(ctx
->shader
, ctx
->state
.vg
.stroke_paint
);
1586 shader_set_paint_matrix(ctx
->shader
, &paint_matrix
);
1587 shader_bind(ctx
->shader
);
1592 void path_fill(struct path
*p
)
1594 struct vg_context
*ctx
= vg_current_context();
1595 struct matrix identity
;
1597 matrix_load_identity(&identity
);
1600 struct polygon_array
*polygon_array
= path_get_fill_polygons(p
, &identity
);
1601 struct array
*polys
= polygon_array
->array
;
1603 if (!polygon_array
|| !polys
|| !polys
->num_elements
) {
1606 polygon_array_fill(polygon_array
, ctx
);
1610 void path_stroke(struct path
*p
)
1612 struct vg_context
*ctx
= vg_current_context();
1613 VGFillRule old_fill
= ctx
->state
.vg
.fill_rule
;
1614 struct matrix identity
;
1615 struct path
*stroke
;
1617 matrix_load_identity(&identity
);
1618 stroke
= path_create_stroke(p
, &identity
);
1619 if (stroke
&& !path_is_empty(stroke
)) {
1620 ctx
->state
.vg
.fill_rule
= VG_NON_ZERO
;
1624 ctx
->state
.vg
.fill_rule
= old_fill
;
1628 void path_move_to(struct path
*p
, float x
, float y
)
1630 VGubyte segment
= VG_MOVE_TO_ABS
;
1631 VGubyte common_data
[sizeof(VGfloat
) * 2];
1632 VGfloat data
[2] = {x
, y
};
1634 vg_float_to_datatype(p
->datatype
, common_data
, data
, 2);
1635 path_append_data(p
, 1, &segment
, common_data
);
1638 void path_line_to(struct path
*p
, float x
, float y
)
1640 VGubyte segment
= VG_LINE_TO_ABS
;
1641 VGubyte common_data
[sizeof(VGfloat
) * 2];
1642 VGfloat data
[2] = {x
, y
};
1644 vg_float_to_datatype(p
->datatype
, common_data
, data
, 2);
1646 path_append_data(p
, 1, &segment
, common_data
);
1649 void path_cubic_to(struct path
*p
, float px1
, float py1
,
1650 float px2
, float py2
,
1653 VGubyte segment
= VG_CUBIC_TO_ABS
;
1654 VGubyte common_data
[sizeof(VGfloat
) * 6];
1657 data
[0] = px1
; data
[1] = py1
;
1658 data
[2] = px2
; data
[3] = py2
;
1659 data
[4] = x
; data
[5] = y
;
1661 vg_float_to_datatype(p
->datatype
, common_data
, data
, 6);
1663 path_append_data(p
, 1, &segment
, common_data
);
1666 static INLINE
void line_bounds(VGfloat
*line
/*x1,y1,x2,y2*/,
1669 bounds
[0] = MIN2(line
[0], line
[2]);
1670 bounds
[1] = MIN2(line
[1], line
[3]);
1671 bounds
[2] = MAX2(line
[0], line
[2]) - bounds
[0];
1672 bounds
[3] = MAX2(line
[1], line
[3]) - bounds
[1];
1675 static INLINE
void unite_bounds(VGfloat
*bounds
,
1678 VGfloat cx1
, cy1
, cx2
, cy2
;
1679 VGfloat nx1
, ny1
, nx2
, ny2
;
1683 cx2
= bounds
[0] + bounds
[2];
1684 cy2
= bounds
[1] + bounds
[3];
1688 nx2
= el
[0] + el
[2];
1689 ny2
= el
[1] + el
[3];
1691 bounds
[0] = MIN2(cx1
, nx1
);
1692 bounds
[1] = MIN2(cy1
, ny1
);
1693 bounds
[2] = MAX2(cx2
, nx2
) - bounds
[0];
1694 bounds
[3] = MAX2(cy2
, ny2
) - bounds
[1];
1697 static INLINE
void set_bounds(VGfloat
*bounds
,
1698 VGfloat
*element_bounds
,
1699 VGboolean
*initialized
)
1701 if (!(*initialized
)) {
1702 memcpy(bounds
, element_bounds
, 4 * sizeof(VGfloat
));
1703 *initialized
= VG_TRUE
;
1705 unite_bounds(bounds
, element_bounds
);
1708 void path_bounding_rect(struct path
*p
, float *x
, float *y
,
1713 struct path_iter_data iter
;
1716 VGfloat element_bounds
[4];
1718 VGboolean bounds_inited
= VG_FALSE
;
1720 memset(&iter
, 0, sizeof(struct path_iter_data
));
1721 memset(&bounds
, 0, sizeof(bounds
));
1723 if (!p
->num_segments
) {
1730 iter
.coords
= p
->control_points
->data
;
1732 for (i
= 0; i
< p
->num_segments
; ++i
) {
1734 iter
.segment
= ((VGubyte
*)(p
->segments
->data
))[i
];
1739 segment
= normalize_coords(&iter
, &num_coords
, coords
);
1743 case VG_MOVE_TO_ABS
:
1745 case VG_LINE_TO_ABS
: {
1746 VGfloat line
[4] = {ox
, oy
, coords
[0], coords
[1]};
1747 line_bounds(line
, element_bounds
);
1748 set_bounds(bounds
, element_bounds
, &bounds_inited
);
1751 case VG_CUBIC_TO_ABS
: {
1752 struct bezier bezier
;
1753 bezier_init(&bezier
, ox
, oy
,
1754 coords
[0], coords
[1],
1755 coords
[2], coords
[3],
1756 coords
[4], coords
[5]);
1757 bezier_exact_bounds(&bezier
, element_bounds
);
1758 set_bounds(bounds
, element_bounds
, &bounds_inited
);
1764 case VG_LCWARC_TO
: {
1766 struct matrix identity
;
1767 struct path
*path
= path_create(VG_PATH_DATATYPE_F
,
1768 1, 0, 0, 0, VG_PATH_CAPABILITY_ALL
);
1770 matrix_load_identity(&identity
);
1771 arc_init(&arc
, segment
,
1772 ox
, oy
, coords
[3], coords
[4],
1773 coords
[0], coords
[1], coords
[2]);
1775 arc_to_path(&arc
, path
, &identity
);
1777 path_bounding_rect(path
, element_bounds
+ 0, element_bounds
+ 1,
1778 element_bounds
+ 2, element_bounds
+ 3);
1779 set_bounds(bounds
, element_bounds
, &bounds_inited
);
1793 float path_length(struct path
*p
, int start_segment
, int num_segments
)
1797 struct path_iter_data iter
;
1801 VGboolean in_range
= VG_FALSE
;
1803 memset(&iter
, 0, sizeof(struct path_iter_data
));
1806 iter
.coords
= p
->control_points
->data
;
1808 for (i
= 0; i
< (start_segment
+ num_segments
); ++i
) {
1811 iter
.segment
= ((VGubyte
*)(p
->segments
->data
))[i
];
1816 segment
= normalize_coords(&iter
, &num_coords
, coords
);
1818 in_range
= (i
>= start_segment
) && i
<= (start_segment
+ num_segments
);
1823 case VG_MOVE_TO_ABS
:
1825 case VG_CLOSE_PATH
: {
1826 VGfloat line
[4] = {ox
, oy
, iter
.sx
, iter
.sy
};
1827 length
+= line_lengthv(line
);
1830 case VG_LINE_TO_ABS
: {
1831 VGfloat line
[4] = {ox
, oy
, coords
[0], coords
[1]};
1832 length
+= line_lengthv(line
);
1835 case VG_CUBIC_TO_ABS
: {
1836 struct bezier bezier
;
1837 bezier_init(&bezier
, ox
, oy
,
1838 coords
[0], coords
[1],
1839 coords
[2], coords
[3],
1840 coords
[4], coords
[5]);
1841 length
+= bezier_length(&bezier
, BEZIER_DEFAULT_ERROR
);
1847 case VG_LCWARC_TO
: {
1849 struct matrix identity
;
1850 struct path
*path
= path_create(VG_PATH_DATATYPE_F
,
1851 1, 0, 0, 0, VG_PATH_CAPABILITY_ALL
);
1853 matrix_load_identity(&identity
);
1854 arc_init(&arc
, segment
,
1855 ox
, oy
, coords
[3], coords
[4],
1856 coords
[0], coords
[1], coords
[2]);
1858 arc_to_path(&arc
, path
, &identity
);
1860 length
+= path_length(path
, 0, path_num_segments(path
));
1871 static INLINE VGboolean
point_on_current_segment(VGfloat distance
,
1873 VGfloat segment_length
)
1876 (((floatIsZero(distance
) || distance
< 0) && floatIsZero(length
)) ||
1877 ((distance
> length
|| floatsEqual(distance
, length
)) &&
1878 (floatsEqual(distance
, length
+ segment_length
) ||
1879 distance
< (length
+ segment_length
))));
1882 static VGboolean
path_point_segment(struct path_iter_data iter
,
1883 struct path_iter_data prev_iter
,
1886 VGfloat length
, VGfloat
*current_length
,
1887 VGfloat
*point
, VGfloat
*normal
)
1889 switch (iter
.segment
) {
1890 case VG_MOVE_TO_ABS
:
1892 case VG_CLOSE_PATH
: {
1893 VGfloat line
[4] = {prev_iter
.ox
, prev_iter
.oy
, iter
.sx
, iter
.sy
};
1894 VGboolean on_current_segment
= VG_FALSE
;
1895 *current_length
= line_lengthv(line
);
1896 on_current_segment
= point_on_current_segment(distance
,
1899 if (on_current_segment
) {
1900 VGfloat at
= (distance
- length
) / line_lengthv(line
);
1901 line_normal_vector(line
, normal
);
1902 line_point_at(line
, at
, point
);
1907 case VG_LINE_TO_ABS
: {
1908 VGfloat line
[4] = {prev_iter
.ox
, prev_iter
.oy
, coords
[0], coords
[1]};
1909 VGboolean on_current_segment
= VG_FALSE
;
1910 *current_length
= line_lengthv(line
);
1911 on_current_segment
= point_on_current_segment(distance
,
1914 if (on_current_segment
) {
1915 VGfloat at
= (distance
- length
) / line_lengthv(line
);
1916 line_normal_vector(line
, normal
);
1917 line_point_at(line
, at
, point
);
1922 case VG_CUBIC_TO_ABS
: {
1923 struct bezier bezier
;
1924 bezier_init(&bezier
, prev_iter
.ox
, prev_iter
.oy
,
1925 coords
[0], coords
[1],
1926 coords
[2], coords
[3],
1927 coords
[4], coords
[5]);
1928 *current_length
= bezier_length(&bezier
, BEZIER_DEFAULT_ERROR
);
1929 if (point_on_current_segment(distance
, length
, *current_length
)) {
1930 bezier_point_at_length(&bezier
, distance
- length
,
1939 case VG_LCWARC_TO
: {
1941 struct matrix identity
;
1942 struct path
*path
= path_create(VG_PATH_DATATYPE_F
,
1943 1, 0, 0, 0, VG_PATH_CAPABILITY_ALL
);
1945 matrix_load_identity(&identity
);
1946 arc_init(&arc
, iter
.segment
,
1947 prev_iter
.ox
, prev_iter
.oy
, coords
[3], coords
[4],
1948 coords
[0], coords
[1], coords
[2]);
1950 arc_to_path(&arc
, path
, &identity
);
1952 *current_length
= path_length(path
, 0, path_num_segments(path
));
1953 if (point_on_current_segment(distance
, length
, *current_length
)) {
1954 path_point(path
, 0, path_num_segments(path
),
1955 distance
- length
, point
, normal
);
1966 void path_point(struct path
*p
, VGint start_segment
, VGint num_segments
,
1967 VGfloat distance
, VGfloat
*point
, VGfloat
*normal
)
1971 struct path_iter_data iter
, prev_iter
;
1974 VGfloat current_length
= 0;
1976 memset(&iter
, 0, sizeof(struct path_iter_data
));
1977 memset(&prev_iter
, 0, sizeof(struct path_iter_data
));
1986 iter
.coords
= p
->control_points
->data
;
1990 for (i
= 0; i
< (start_segment
+ num_segments
); ++i
) {
1991 VGboolean outside_range
= (i
< start_segment
||
1992 i
>= (start_segment
+ num_segments
));
1996 iter
.segment
= ((VGubyte
*)(p
->segments
->data
))[i
];
1997 iter
.segment
= normalize_coords(&iter
, &num_coords
, coords
);
2002 if (path_point_segment(iter
, prev_iter
, coords
,
2003 distance
, length
, ¤t_length
,
2007 length
+= current_length
;
2011 *OpenVG 1.0 - 8.6.11 vgPointAlongPath
2013 * If distance is greater than or equal to the path length
2014 *(i.e., the value returned by vgPathLength when called with the same
2015 *startSegment and numSegments parameters), the visual ending point of
2019 switch (iter
.segment
) {
2020 case VG_MOVE_TO_ABS
:
2022 case VG_CLOSE_PATH
: {
2023 VGfloat line
[4] = {prev_iter
.ox
, prev_iter
.oy
, iter
.sx
, iter
.sy
};
2024 line_normal_vector(line
, normal
);
2025 line_point_at(line
, 1.f
, point
);
2028 case VG_LINE_TO_ABS
: {
2029 VGfloat line
[4] = {prev_iter
.ox
, prev_iter
.oy
, coords
[0], coords
[1]};
2030 line_normal_vector(line
, normal
);
2031 line_point_at(line
, 1.f
, point
);
2034 case VG_CUBIC_TO_ABS
: {
2035 struct bezier bezier
;
2036 bezier_init(&bezier
, prev_iter
.ox
, prev_iter
.oy
,
2037 coords
[0], coords
[1],
2038 coords
[2], coords
[3],
2039 coords
[4], coords
[5]);
2040 bezier_point_at_t(&bezier
, 1.f
, point
, normal
);
2046 case VG_LCWARC_TO
: {
2048 struct matrix identity
;
2049 struct path
*path
= path_create(VG_PATH_DATATYPE_F
,
2050 1, 0, 0, 0, VG_PATH_CAPABILITY_ALL
);
2052 matrix_load_identity(&identity
);
2053 arc_init(&arc
, iter
.segment
,
2054 prev_iter
.ox
, prev_iter
.oy
, coords
[3], coords
[4],
2055 coords
[0], coords
[1], coords
[2]);
2057 arc_to_path(&arc
, path
, &identity
);
2059 path_point(path
, 0, path_num_segments(path
),
2060 /* to make sure we're bigger than len * 2 it */
2061 2 * path_length(path
, 0, path_num_segments(path
)),
2071 VGboolean
path_is_empty(struct path
*p
)
2073 return p
->segments
->num_elements
== 0;