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_CLOSE_PATH
||
168 pathSegments
[i
] > VG_LCWARC_TO_REL
) {
169 vg_set_error(ctx
, VG_ILLEGAL_ARGUMENT_ERROR
);
174 p
= (struct path
*)dstPath
;
176 if (!pathData
|| !is_aligned_to(pathData
, path_datatype_size(p
))) {
177 vg_set_error(ctx
, VG_ILLEGAL_ARGUMENT_ERROR
);
181 if (!(path_capabilities(p
)&VG_PATH_CAPABILITY_APPEND_TO
)) {
182 vg_set_error(ctx
, VG_PATH_CAPABILITY_ERROR
);
186 path_append_data(p
, numSegments
, pathSegments
, pathData
);
189 void vgModifyPathCoords(VGPath dstPath
,
192 const void * pathData
)
194 struct vg_context
*ctx
= vg_current_context();
197 if (dstPath
== VG_INVALID_HANDLE
) {
198 vg_set_error(ctx
, VG_BAD_HANDLE_ERROR
);
201 if (startIndex
< 0 || numSegments
<= 0) {
202 vg_set_error(ctx
, VG_ILLEGAL_ARGUMENT_ERROR
);
206 p
= (struct path
*)dstPath
;
208 if (!pathData
|| !is_aligned_to(pathData
, path_datatype_size(p
))) {
209 vg_set_error(ctx
, VG_ILLEGAL_ARGUMENT_ERROR
);
213 if (startIndex
+ numSegments
> path_num_segments(p
)) {
214 vg_set_error(ctx
, VG_ILLEGAL_ARGUMENT_ERROR
);
217 if (!(path_capabilities(p
)&VG_PATH_CAPABILITY_MODIFY
)) {
218 vg_set_error(ctx
, VG_PATH_CAPABILITY_ERROR
);
221 path_modify_coords(p
, startIndex
, numSegments
, pathData
);
224 void vgTransformPath(VGPath dstPath
, VGPath srcPath
)
226 struct vg_context
*ctx
= vg_current_context();
227 struct path
*src
= 0, *dst
= 0;
229 if (dstPath
== VG_INVALID_HANDLE
|| srcPath
== VG_INVALID_HANDLE
) {
230 vg_set_error(ctx
, VG_BAD_HANDLE_ERROR
);
233 src
= (struct path
*)srcPath
;
234 dst
= (struct path
*)dstPath
;
236 if (!(path_capabilities(src
) & VG_PATH_CAPABILITY_TRANSFORM_FROM
) ||
237 !(path_capabilities(dst
) & VG_PATH_CAPABILITY_TRANSFORM_TO
)) {
238 vg_set_error(ctx
, VG_PATH_CAPABILITY_ERROR
);
241 path_transform(dst
, src
);
244 VGboolean
vgInterpolatePath(VGPath dstPath
,
249 struct vg_context
*ctx
= vg_current_context();
250 struct path
*start
= 0, *dst
= 0, *end
= 0;
252 if (dstPath
== VG_INVALID_HANDLE
||
253 startPath
== VG_INVALID_HANDLE
||
254 endPath
== VG_INVALID_HANDLE
) {
255 vg_set_error(ctx
, VG_BAD_HANDLE_ERROR
);
258 dst
= (struct path
*)dstPath
;
259 start
= (struct path
*)startPath
;
260 end
= (struct path
*)endPath
;
262 if (!(path_capabilities(dst
) & VG_PATH_CAPABILITY_INTERPOLATE_TO
) ||
263 !(path_capabilities(start
) & VG_PATH_CAPABILITY_INTERPOLATE_FROM
) ||
264 !(path_capabilities(end
) & VG_PATH_CAPABILITY_INTERPOLATE_FROM
)) {
265 vg_set_error(ctx
, VG_PATH_CAPABILITY_ERROR
);
269 return path_interpolate(dst
,
273 VGfloat
vgPathLength(VGPath path
,
277 struct vg_context
*ctx
= vg_current_context();
280 if (path
== VG_INVALID_HANDLE
) {
281 vg_set_error(ctx
, VG_BAD_HANDLE_ERROR
);
284 if (startSegment
< 0) {
285 vg_set_error(ctx
, VG_ILLEGAL_ARGUMENT_ERROR
);
288 if (numSegments
<= 0) {
289 vg_set_error(ctx
, VG_ILLEGAL_ARGUMENT_ERROR
);
292 p
= (struct path
*)path
;
294 if (!(path_capabilities(p
) & VG_PATH_CAPABILITY_PATH_LENGTH
)) {
295 vg_set_error(ctx
, VG_PATH_CAPABILITY_ERROR
);
298 if (startSegment
+ numSegments
> path_num_segments(p
)) {
299 vg_set_error(ctx
, VG_ILLEGAL_ARGUMENT_ERROR
);
303 return path_length(p
, startSegment
, numSegments
);
306 void vgPointAlongPath(VGPath path
,
310 VGfloat
* x
, VGfloat
* y
,
314 struct vg_context
*ctx
= vg_current_context();
318 if (path
== VG_INVALID_HANDLE
) {
319 vg_set_error(ctx
, VG_BAD_HANDLE_ERROR
);
322 if (startSegment
< 0) {
323 vg_set_error(ctx
, VG_ILLEGAL_ARGUMENT_ERROR
);
326 if (numSegments
<= 0) {
327 vg_set_error(ctx
, VG_ILLEGAL_ARGUMENT_ERROR
);
331 if (!is_aligned(x
) || !is_aligned(y
) ||
332 !is_aligned(tangentX
) || !is_aligned(tangentY
)) {
333 vg_set_error(ctx
, VG_ILLEGAL_ARGUMENT_ERROR
);
337 p
= (struct path
*)path
;
339 caps
= path_capabilities(p
);
340 if (!(caps
& VG_PATH_CAPABILITY_POINT_ALONG_PATH
) ||
341 !(caps
& VG_PATH_CAPABILITY_TANGENT_ALONG_PATH
)) {
342 vg_set_error(ctx
, VG_PATH_CAPABILITY_ERROR
);
346 if (startSegment
+ numSegments
> path_num_segments(p
)) {
347 vg_set_error(ctx
, VG_ILLEGAL_ARGUMENT_ERROR
);
352 VGfloat point
[2], normal
[2];
353 path_point(p
, startSegment
, numSegments
, distance
,
360 *tangentX
= -normal
[1];
362 *tangentY
= normal
[0];
366 void vgPathBounds(VGPath path
,
372 struct vg_context
*ctx
= vg_current_context();
376 if (path
== VG_INVALID_HANDLE
) {
377 vg_set_error(ctx
, VG_BAD_HANDLE_ERROR
);
381 if (!minX
|| !minY
|| !width
|| !height
) {
382 vg_set_error(ctx
, VG_ILLEGAL_ARGUMENT_ERROR
);
386 if (!is_aligned(minX
) || !is_aligned(minY
) ||
387 !is_aligned(width
) || !is_aligned(height
)) {
388 vg_set_error(ctx
, VG_ILLEGAL_ARGUMENT_ERROR
);
392 p
= (struct path
*)path
;
394 caps
= path_capabilities(p
);
395 if (!(caps
& VG_PATH_CAPABILITY_PATH_BOUNDS
)) {
396 vg_set_error(ctx
, VG_PATH_CAPABILITY_ERROR
);
400 path_bounding_rect(p
, minX
, minY
, width
, height
);
403 void vgPathTransformedBounds(VGPath path
,
409 struct vg_context
*ctx
= vg_current_context();
413 if (path
== VG_INVALID_HANDLE
) {
414 vg_set_error(ctx
, VG_BAD_HANDLE_ERROR
);
418 if (!minX
|| !minY
|| !width
|| !height
) {
419 vg_set_error(ctx
, VG_ILLEGAL_ARGUMENT_ERROR
);
423 if (!is_aligned(minX
) || !is_aligned(minY
) ||
424 !is_aligned(width
) || !is_aligned(height
)) {
425 vg_set_error(ctx
, VG_ILLEGAL_ARGUMENT_ERROR
);
429 p
= (struct path
*)path
;
431 caps
= path_capabilities(p
);
432 if (!(caps
& VG_PATH_CAPABILITY_PATH_TRANSFORMED_BOUNDS
)) {
433 vg_set_error(ctx
, VG_PATH_CAPABILITY_ERROR
);
438 /* faster, but seems to have precision problems... */
439 path_bounding_rect(p
, minX
, minY
, width
, height
);
440 if (*width
> 0 && *height
> 0) {
441 VGfloat pts
[] = {*minX
, *minY
,
442 *minX
+ *width
, *minY
,
443 *minX
+ *width
, *minY
+ *height
,
444 *minX
, *minY
+ *height
};
445 struct matrix
*matrix
= &ctx
->state
.vg
.path_user_to_surface_matrix
;
447 matrix_map_point(matrix
, pts
[0], pts
[1], pts
+ 0, pts
+ 1);
448 matrix_map_point(matrix
, pts
[2], pts
[3], pts
+ 2, pts
+ 3);
449 matrix_map_point(matrix
, pts
[4], pts
[5], pts
+ 4, pts
+ 5);
450 matrix_map_point(matrix
, pts
[6], pts
[7], pts
+ 6, pts
+ 7);
451 *minX
= MIN2(pts
[0], MIN2(pts
[2], MIN2(pts
[4], pts
[6])));
452 *minY
= MIN2(pts
[1], MIN2(pts
[3], MIN2(pts
[5], pts
[7])));
453 maxX
= MAX2(pts
[0], MAX2(pts
[2], MAX2(pts
[4], pts
[6])));
454 maxY
= MAX2(pts
[1], MAX2(pts
[3], MAX2(pts
[5], pts
[7])));
455 *width
= maxX
- *minX
;
456 *height
= maxY
- *minY
;
460 struct path
*dst
= path_create(VG_PATH_DATATYPE_F
, 1.0, 0,
461 0, 0, VG_PATH_CAPABILITY_ALL
);
462 path_transform(dst
, p
);
463 path_bounding_rect(dst
, minX
, minY
, width
, height
);
470 void vgDrawPath(VGPath path
, VGbitfield paintModes
)
472 struct vg_context
*ctx
= vg_current_context();
474 if (path
== VG_INVALID_HANDLE
) {
475 vg_set_error(ctx
, VG_BAD_HANDLE_ERROR
);
479 if (!(paintModes
& (VG_STROKE_PATH
| VG_FILL_PATH
))) {
480 vg_set_error(ctx
, VG_ILLEGAL_ARGUMENT_ERROR
);
484 if (path_is_empty((struct path
*)path
))
486 path_render((struct path
*)path
, paintModes
);