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 **************************************************************************/
27 #include "VG/openvg.h"
29 #include "vg_context.h"
34 #include "pipe/p_context.h"
35 #include "pipe/p_inlines.h"
36 #include "util/u_draw_quad.h"
38 VGPath
vgCreatePath(VGint pathFormat
,
39 VGPathDatatype datatype
,
40 VGfloat scale
, VGfloat bias
,
41 VGint segmentCapacityHint
,
42 VGint coordCapacityHint
,
43 VGbitfield capabilities
)
45 struct vg_context
*ctx
= vg_current_context();
47 if (pathFormat
!= VG_PATH_FORMAT_STANDARD
) {
48 vg_set_error(ctx
, VG_UNSUPPORTED_PATH_FORMAT_ERROR
);
49 return VG_INVALID_HANDLE
;
51 if (datatype
< VG_PATH_DATATYPE_S_8
||
52 datatype
> VG_PATH_DATATYPE_F
) {
53 vg_set_error(ctx
, VG_ILLEGAL_ARGUMENT_ERROR
);
54 return VG_INVALID_HANDLE
;
57 vg_set_error(ctx
, VG_ILLEGAL_ARGUMENT_ERROR
);
58 return VG_INVALID_HANDLE
;
61 return (VGPath
)path_create(datatype
, scale
, bias
,
62 segmentCapacityHint
, coordCapacityHint
,
66 void vgClearPath(VGPath path
, VGbitfield capabilities
)
68 struct vg_context
*ctx
= vg_current_context();
71 if (path
== VG_INVALID_HANDLE
) {
72 vg_set_error(ctx
, VG_BAD_HANDLE_ERROR
);
76 p
= (struct path
*)path
;
77 path_clear(p
, capabilities
);
80 void vgDestroyPath(VGPath p
)
82 struct path
*path
= 0;
83 struct vg_context
*ctx
= vg_current_context();
85 if (p
== VG_INVALID_HANDLE
) {
86 vg_set_error(ctx
, VG_BAD_HANDLE_ERROR
);
90 path
= (struct path
*)p
;
94 void vgRemovePathCapabilities(VGPath path
,
95 VGbitfield capabilities
)
97 struct vg_context
*ctx
= vg_current_context();
101 if (path
== VG_INVALID_HANDLE
) {
102 vg_set_error(ctx
, VG_BAD_HANDLE_ERROR
);
106 p
= (struct path
*)path
;
107 current
= path_capabilities(p
);
108 path_set_capabilities(p
, (current
&
109 (~(capabilities
& VG_PATH_CAPABILITY_ALL
))));
112 VGbitfield
vgGetPathCapabilities(VGPath path
)
114 struct vg_context
*ctx
= vg_current_context();
117 if (path
== VG_INVALID_HANDLE
) {
118 vg_set_error(ctx
, VG_BAD_HANDLE_ERROR
);
121 p
= (struct path
*)path
;
122 return path_capabilities(p
);
125 void vgAppendPath(VGPath dstPath
, VGPath srcPath
)
127 struct vg_context
*ctx
= vg_current_context();
128 struct path
*src
, *dst
;
130 if (dstPath
== VG_INVALID_HANDLE
|| srcPath
== VG_INVALID_HANDLE
) {
131 vg_set_error(ctx
, VG_BAD_HANDLE_ERROR
);
134 src
= (struct path
*)srcPath
;
135 dst
= (struct path
*)dstPath
;
137 if (!(path_capabilities(src
) & VG_PATH_CAPABILITY_APPEND_FROM
) ||
138 !(path_capabilities(dst
) & VG_PATH_CAPABILITY_APPEND_TO
)) {
139 vg_set_error(ctx
, VG_PATH_CAPABILITY_ERROR
);
142 path_append_path(dst
, src
);
145 void vgAppendPathData(VGPath dstPath
,
147 const VGubyte
* pathSegments
,
148 const void * pathData
)
150 struct vg_context
*ctx
= vg_current_context();
154 if (dstPath
== VG_INVALID_HANDLE
) {
155 vg_set_error(ctx
, VG_BAD_HANDLE_ERROR
);
159 vg_set_error(ctx
, VG_ILLEGAL_ARGUMENT_ERROR
);
162 if (numSegments
<= 0) {
163 vg_set_error(ctx
, VG_ILLEGAL_ARGUMENT_ERROR
);
166 for (i
= 0; i
< numSegments
; ++i
) {
167 if (pathSegments
[i
] > VG_LCWARC_TO_REL
) {
168 vg_set_error(ctx
, VG_ILLEGAL_ARGUMENT_ERROR
);
173 p
= (struct path
*)dstPath
;
175 if (!pathData
|| !is_aligned_to(pathData
, path_datatype_size(p
))) {
176 vg_set_error(ctx
, VG_ILLEGAL_ARGUMENT_ERROR
);
180 if (!(path_capabilities(p
)&VG_PATH_CAPABILITY_APPEND_TO
)) {
181 vg_set_error(ctx
, VG_PATH_CAPABILITY_ERROR
);
185 path_append_data(p
, numSegments
, pathSegments
, pathData
);
188 void vgModifyPathCoords(VGPath dstPath
,
191 const void * pathData
)
193 struct vg_context
*ctx
= vg_current_context();
196 if (dstPath
== VG_INVALID_HANDLE
) {
197 vg_set_error(ctx
, VG_BAD_HANDLE_ERROR
);
200 if (startIndex
< 0 || numSegments
<= 0) {
201 vg_set_error(ctx
, VG_ILLEGAL_ARGUMENT_ERROR
);
205 p
= (struct path
*)dstPath
;
207 if (!pathData
|| !is_aligned_to(pathData
, path_datatype_size(p
))) {
208 vg_set_error(ctx
, VG_ILLEGAL_ARGUMENT_ERROR
);
212 if (startIndex
+ numSegments
> path_num_segments(p
)) {
213 vg_set_error(ctx
, VG_ILLEGAL_ARGUMENT_ERROR
);
216 if (!(path_capabilities(p
)&VG_PATH_CAPABILITY_MODIFY
)) {
217 vg_set_error(ctx
, VG_PATH_CAPABILITY_ERROR
);
220 path_modify_coords(p
, startIndex
, numSegments
, pathData
);
223 void vgTransformPath(VGPath dstPath
, VGPath srcPath
)
225 struct vg_context
*ctx
= vg_current_context();
226 struct path
*src
= 0, *dst
= 0;
228 if (dstPath
== VG_INVALID_HANDLE
|| srcPath
== VG_INVALID_HANDLE
) {
229 vg_set_error(ctx
, VG_BAD_HANDLE_ERROR
);
232 src
= (struct path
*)srcPath
;
233 dst
= (struct path
*)dstPath
;
235 if (!(path_capabilities(src
) & VG_PATH_CAPABILITY_TRANSFORM_FROM
) ||
236 !(path_capabilities(dst
) & VG_PATH_CAPABILITY_TRANSFORM_TO
)) {
237 vg_set_error(ctx
, VG_PATH_CAPABILITY_ERROR
);
240 path_transform(dst
, src
);
243 VGboolean
vgInterpolatePath(VGPath dstPath
,
248 struct vg_context
*ctx
= vg_current_context();
249 struct path
*start
= 0, *dst
= 0, *end
= 0;
251 if (dstPath
== VG_INVALID_HANDLE
||
252 startPath
== VG_INVALID_HANDLE
||
253 endPath
== VG_INVALID_HANDLE
) {
254 vg_set_error(ctx
, VG_BAD_HANDLE_ERROR
);
257 dst
= (struct path
*)dstPath
;
258 start
= (struct path
*)startPath
;
259 end
= (struct path
*)endPath
;
261 if (!(path_capabilities(dst
) & VG_PATH_CAPABILITY_INTERPOLATE_TO
) ||
262 !(path_capabilities(start
) & VG_PATH_CAPABILITY_INTERPOLATE_FROM
) ||
263 !(path_capabilities(end
) & VG_PATH_CAPABILITY_INTERPOLATE_FROM
)) {
264 vg_set_error(ctx
, VG_PATH_CAPABILITY_ERROR
);
268 return path_interpolate(dst
,
272 VGfloat
vgPathLength(VGPath path
,
276 struct vg_context
*ctx
= vg_current_context();
279 if (path
== VG_INVALID_HANDLE
) {
280 vg_set_error(ctx
, VG_BAD_HANDLE_ERROR
);
283 if (startSegment
< 0) {
284 vg_set_error(ctx
, VG_ILLEGAL_ARGUMENT_ERROR
);
287 if (numSegments
<= 0) {
288 vg_set_error(ctx
, VG_ILLEGAL_ARGUMENT_ERROR
);
291 p
= (struct path
*)path
;
293 if (!(path_capabilities(p
) & VG_PATH_CAPABILITY_PATH_LENGTH
)) {
294 vg_set_error(ctx
, VG_PATH_CAPABILITY_ERROR
);
297 if (startSegment
+ numSegments
> path_num_segments(p
)) {
298 vg_set_error(ctx
, VG_ILLEGAL_ARGUMENT_ERROR
);
302 return path_length(p
, startSegment
, numSegments
);
305 void vgPointAlongPath(VGPath path
,
309 VGfloat
* x
, VGfloat
* y
,
313 struct vg_context
*ctx
= vg_current_context();
317 if (path
== VG_INVALID_HANDLE
) {
318 vg_set_error(ctx
, VG_BAD_HANDLE_ERROR
);
321 if (startSegment
< 0) {
322 vg_set_error(ctx
, VG_ILLEGAL_ARGUMENT_ERROR
);
325 if (numSegments
<= 0) {
326 vg_set_error(ctx
, VG_ILLEGAL_ARGUMENT_ERROR
);
330 if (!is_aligned(x
) || !is_aligned(y
) ||
331 !is_aligned(tangentX
) || !is_aligned(tangentY
)) {
332 vg_set_error(ctx
, VG_ILLEGAL_ARGUMENT_ERROR
);
336 p
= (struct path
*)path
;
338 caps
= path_capabilities(p
);
339 if (!(caps
& VG_PATH_CAPABILITY_POINT_ALONG_PATH
) ||
340 !(caps
& VG_PATH_CAPABILITY_TANGENT_ALONG_PATH
)) {
341 vg_set_error(ctx
, VG_PATH_CAPABILITY_ERROR
);
345 if (startSegment
+ numSegments
> path_num_segments(p
)) {
346 vg_set_error(ctx
, VG_ILLEGAL_ARGUMENT_ERROR
);
351 VGfloat point
[2], normal
[2];
352 path_point(p
, startSegment
, numSegments
, distance
,
359 *tangentX
= -normal
[1];
361 *tangentY
= normal
[0];
365 void vgPathBounds(VGPath path
,
371 struct vg_context
*ctx
= vg_current_context();
375 if (path
== VG_INVALID_HANDLE
) {
376 vg_set_error(ctx
, VG_BAD_HANDLE_ERROR
);
380 if (!minX
|| !minY
|| !width
|| !height
) {
381 vg_set_error(ctx
, VG_ILLEGAL_ARGUMENT_ERROR
);
385 if (!is_aligned(minX
) || !is_aligned(minY
) ||
386 !is_aligned(width
) || !is_aligned(height
)) {
387 vg_set_error(ctx
, VG_ILLEGAL_ARGUMENT_ERROR
);
391 p
= (struct path
*)path
;
393 caps
= path_capabilities(p
);
394 if (!(caps
& VG_PATH_CAPABILITY_PATH_BOUNDS
)) {
395 vg_set_error(ctx
, VG_PATH_CAPABILITY_ERROR
);
399 path_bounding_rect(p
, minX
, minY
, width
, height
);
402 void vgPathTransformedBounds(VGPath path
,
408 struct vg_context
*ctx
= vg_current_context();
412 if (path
== VG_INVALID_HANDLE
) {
413 vg_set_error(ctx
, VG_BAD_HANDLE_ERROR
);
417 if (!minX
|| !minY
|| !width
|| !height
) {
418 vg_set_error(ctx
, VG_ILLEGAL_ARGUMENT_ERROR
);
422 if (!is_aligned(minX
) || !is_aligned(minY
) ||
423 !is_aligned(width
) || !is_aligned(height
)) {
424 vg_set_error(ctx
, VG_ILLEGAL_ARGUMENT_ERROR
);
428 p
= (struct path
*)path
;
430 caps
= path_capabilities(p
);
431 if (!(caps
& VG_PATH_CAPABILITY_PATH_TRANSFORMED_BOUNDS
)) {
432 vg_set_error(ctx
, VG_PATH_CAPABILITY_ERROR
);
437 /* faster, but seems to have precision problems... */
438 path_bounding_rect(p
, minX
, minY
, width
, height
);
439 if (*width
> 0 && *height
> 0) {
440 VGfloat pts
[] = {*minX
, *minY
,
441 *minX
+ *width
, *minY
,
442 *minX
+ *width
, *minY
+ *height
,
443 *minX
, *minY
+ *height
};
444 struct matrix
*matrix
= &ctx
->state
.vg
.path_user_to_surface_matrix
;
446 matrix_map_point(matrix
, pts
[0], pts
[1], pts
+ 0, pts
+ 1);
447 matrix_map_point(matrix
, pts
[2], pts
[3], pts
+ 2, pts
+ 3);
448 matrix_map_point(matrix
, pts
[4], pts
[5], pts
+ 4, pts
+ 5);
449 matrix_map_point(matrix
, pts
[6], pts
[7], pts
+ 6, pts
+ 7);
450 *minX
= MIN2(pts
[0], MIN2(pts
[2], MIN2(pts
[4], pts
[6])));
451 *minY
= MIN2(pts
[1], MIN2(pts
[3], MIN2(pts
[5], pts
[7])));
452 maxX
= MAX2(pts
[0], MAX2(pts
[2], MAX2(pts
[4], pts
[6])));
453 maxY
= MAX2(pts
[1], MAX2(pts
[3], MAX2(pts
[5], pts
[7])));
454 *width
= maxX
- *minX
;
455 *height
= maxY
- *minY
;
459 struct path
*dst
= path_create(VG_PATH_DATATYPE_F
, 1.0, 0,
460 0, 0, VG_PATH_CAPABILITY_ALL
);
461 path_transform(dst
, p
);
462 path_bounding_rect(dst
, minX
, minY
, width
, height
);
469 void vgDrawPath(VGPath path
, VGbitfield paintModes
)
471 struct vg_context
*ctx
= vg_current_context();
473 if (path
== VG_INVALID_HANDLE
) {
474 vg_set_error(ctx
, VG_BAD_HANDLE_ERROR
);
478 if (!(paintModes
& (VG_STROKE_PATH
| VG_FILL_PATH
))) {
479 vg_set_error(ctx
, VG_ILLEGAL_ARGUMENT_ERROR
);
483 if (path_is_empty((struct path
*)path
))
485 path_render((struct path
*)path
, paintModes
);