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"
36 VGPath
vegaCreatePath(VGint pathFormat
,
37 VGPathDatatype datatype
,
38 VGfloat scale
, VGfloat bias
,
39 VGint segmentCapacityHint
,
40 VGint coordCapacityHint
,
41 VGbitfield capabilities
)
43 struct vg_context
*ctx
= vg_current_context();
45 if (pathFormat
!= VG_PATH_FORMAT_STANDARD
) {
46 vg_set_error(ctx
, VG_UNSUPPORTED_PATH_FORMAT_ERROR
);
47 return VG_INVALID_HANDLE
;
49 if (datatype
< VG_PATH_DATATYPE_S_8
||
50 datatype
> VG_PATH_DATATYPE_F
) {
51 vg_set_error(ctx
, VG_ILLEGAL_ARGUMENT_ERROR
);
52 return VG_INVALID_HANDLE
;
55 vg_set_error(ctx
, VG_ILLEGAL_ARGUMENT_ERROR
);
56 return VG_INVALID_HANDLE
;
59 return path_to_handle(path_create(datatype
, scale
, bias
,
60 segmentCapacityHint
, coordCapacityHint
,
64 void vegaClearPath(VGPath path
, VGbitfield capabilities
)
66 struct vg_context
*ctx
= vg_current_context();
69 if (path
== VG_INVALID_HANDLE
) {
70 vg_set_error(ctx
, VG_BAD_HANDLE_ERROR
);
74 p
= handle_to_path(path
);
75 path_clear(p
, capabilities
);
78 void vegaDestroyPath(VGPath p
)
80 struct path
*path
= 0;
81 struct vg_context
*ctx
= vg_current_context();
83 if (p
== VG_INVALID_HANDLE
) {
84 vg_set_error(ctx
, VG_BAD_HANDLE_ERROR
);
88 path
= handle_to_path(p
);
92 void vegaRemovePathCapabilities(VGPath path
,
93 VGbitfield capabilities
)
95 struct vg_context
*ctx
= vg_current_context();
99 if (path
== VG_INVALID_HANDLE
) {
100 vg_set_error(ctx
, VG_BAD_HANDLE_ERROR
);
104 p
= handle_to_path(path
);
105 current
= path_capabilities(p
);
106 path_set_capabilities(p
, (current
&
107 (~(capabilities
& VG_PATH_CAPABILITY_ALL
))));
110 VGbitfield
vegaGetPathCapabilities(VGPath path
)
112 struct vg_context
*ctx
= vg_current_context();
115 if (path
== VG_INVALID_HANDLE
) {
116 vg_set_error(ctx
, VG_BAD_HANDLE_ERROR
);
119 p
= handle_to_path(path
);
120 return path_capabilities(p
);
123 void vegaAppendPath(VGPath dstPath
, VGPath srcPath
)
125 struct vg_context
*ctx
= vg_current_context();
126 struct path
*src
, *dst
;
128 if (dstPath
== VG_INVALID_HANDLE
|| srcPath
== VG_INVALID_HANDLE
) {
129 vg_set_error(ctx
, VG_BAD_HANDLE_ERROR
);
132 src
= handle_to_path(srcPath
);
133 dst
= handle_to_path(dstPath
);
135 if (!(path_capabilities(src
) & VG_PATH_CAPABILITY_APPEND_FROM
) ||
136 !(path_capabilities(dst
) & VG_PATH_CAPABILITY_APPEND_TO
)) {
137 vg_set_error(ctx
, VG_PATH_CAPABILITY_ERROR
);
140 path_append_path(dst
, src
);
143 void vegaAppendPathData(VGPath dstPath
,
145 const VGubyte
* pathSegments
,
146 const void * pathData
)
148 struct vg_context
*ctx
= vg_current_context();
152 if (dstPath
== VG_INVALID_HANDLE
) {
153 vg_set_error(ctx
, VG_BAD_HANDLE_ERROR
);
157 vg_set_error(ctx
, VG_ILLEGAL_ARGUMENT_ERROR
);
160 if (numSegments
<= 0) {
161 vg_set_error(ctx
, VG_ILLEGAL_ARGUMENT_ERROR
);
164 for (i
= 0; i
< numSegments
; ++i
) {
165 if (pathSegments
[i
] > VG_LCWARC_TO_REL
) {
166 vg_set_error(ctx
, VG_ILLEGAL_ARGUMENT_ERROR
);
171 p
= handle_to_path(dstPath
);
173 if (!p
|| !is_aligned_to(p
, path_datatype_size(p
))) {
174 vg_set_error(ctx
, VG_ILLEGAL_ARGUMENT_ERROR
);
178 if (!(path_capabilities(p
)&VG_PATH_CAPABILITY_APPEND_TO
)) {
179 vg_set_error(ctx
, VG_PATH_CAPABILITY_ERROR
);
183 path_append_data(p
, numSegments
, pathSegments
, pathData
);
186 void vegaModifyPathCoords(VGPath dstPath
,
189 const void * pathData
)
191 struct vg_context
*ctx
= vg_current_context();
194 if (dstPath
== VG_INVALID_HANDLE
) {
195 vg_set_error(ctx
, VG_BAD_HANDLE_ERROR
);
198 if (startIndex
< 0 || numSegments
<= 0) {
199 vg_set_error(ctx
, VG_ILLEGAL_ARGUMENT_ERROR
);
203 p
= handle_to_path(dstPath
);
205 if (!pathData
|| !is_aligned_to(pathData
, path_datatype_size(p
))) {
206 vg_set_error(ctx
, VG_ILLEGAL_ARGUMENT_ERROR
);
210 if (startIndex
+ numSegments
> path_num_segments(p
)) {
211 vg_set_error(ctx
, VG_ILLEGAL_ARGUMENT_ERROR
);
214 if (!(path_capabilities(p
)&VG_PATH_CAPABILITY_MODIFY
)) {
215 vg_set_error(ctx
, VG_PATH_CAPABILITY_ERROR
);
218 path_modify_coords(p
, startIndex
, numSegments
, pathData
);
221 void vegaTransformPath(VGPath dstPath
, VGPath srcPath
)
223 struct vg_context
*ctx
= vg_current_context();
224 struct path
*src
= 0, *dst
= 0;
226 if (dstPath
== VG_INVALID_HANDLE
|| srcPath
== VG_INVALID_HANDLE
) {
227 vg_set_error(ctx
, VG_BAD_HANDLE_ERROR
);
230 src
= handle_to_path(srcPath
);
231 dst
= handle_to_path(dstPath
);
233 if (!(path_capabilities(src
) & VG_PATH_CAPABILITY_TRANSFORM_FROM
) ||
234 !(path_capabilities(dst
) & VG_PATH_CAPABILITY_TRANSFORM_TO
)) {
235 vg_set_error(ctx
, VG_PATH_CAPABILITY_ERROR
);
238 path_transform(dst
, src
);
241 VGboolean
vegaInterpolatePath(VGPath dstPath
,
246 struct vg_context
*ctx
= vg_current_context();
247 struct path
*start
= 0, *dst
= 0, *end
= 0;
249 if (dstPath
== VG_INVALID_HANDLE
||
250 startPath
== VG_INVALID_HANDLE
||
251 endPath
== VG_INVALID_HANDLE
) {
252 vg_set_error(ctx
, VG_BAD_HANDLE_ERROR
);
255 dst
= handle_to_path(dstPath
);
256 start
= handle_to_path(startPath
);
257 end
= handle_to_path(endPath
);
259 if (!(path_capabilities(dst
) & VG_PATH_CAPABILITY_INTERPOLATE_TO
) ||
260 !(path_capabilities(start
) & VG_PATH_CAPABILITY_INTERPOLATE_FROM
) ||
261 !(path_capabilities(end
) & VG_PATH_CAPABILITY_INTERPOLATE_FROM
)) {
262 vg_set_error(ctx
, VG_PATH_CAPABILITY_ERROR
);
266 return path_interpolate(dst
,
270 VGfloat
vegaPathLength(VGPath path
,
274 struct vg_context
*ctx
= vg_current_context();
277 if (path
== VG_INVALID_HANDLE
) {
278 vg_set_error(ctx
, VG_BAD_HANDLE_ERROR
);
281 if (startSegment
< 0) {
282 vg_set_error(ctx
, VG_ILLEGAL_ARGUMENT_ERROR
);
285 if (numSegments
<= 0) {
286 vg_set_error(ctx
, VG_ILLEGAL_ARGUMENT_ERROR
);
289 p
= handle_to_path(path
);
291 if (!(path_capabilities(p
) & VG_PATH_CAPABILITY_PATH_LENGTH
)) {
292 vg_set_error(ctx
, VG_PATH_CAPABILITY_ERROR
);
295 if (startSegment
+ numSegments
> path_num_segments(p
)) {
296 vg_set_error(ctx
, VG_ILLEGAL_ARGUMENT_ERROR
);
300 return path_length(p
, startSegment
, numSegments
);
303 void vegaPointAlongPath(VGPath path
,
307 VGfloat
* x
, VGfloat
* y
,
311 struct vg_context
*ctx
= vg_current_context();
315 if (path
== VG_INVALID_HANDLE
) {
316 vg_set_error(ctx
, VG_BAD_HANDLE_ERROR
);
319 if (startSegment
< 0) {
320 vg_set_error(ctx
, VG_ILLEGAL_ARGUMENT_ERROR
);
323 if (numSegments
<= 0) {
324 vg_set_error(ctx
, VG_ILLEGAL_ARGUMENT_ERROR
);
328 if (!is_aligned(x
) || !is_aligned(y
) ||
329 !is_aligned(tangentX
) || !is_aligned(tangentY
)) {
330 vg_set_error(ctx
, VG_ILLEGAL_ARGUMENT_ERROR
);
334 p
= handle_to_path(path
);
336 caps
= path_capabilities(p
);
337 if (!(caps
& VG_PATH_CAPABILITY_POINT_ALONG_PATH
) ||
338 !(caps
& VG_PATH_CAPABILITY_TANGENT_ALONG_PATH
)) {
339 vg_set_error(ctx
, VG_PATH_CAPABILITY_ERROR
);
343 if (startSegment
+ numSegments
> path_num_segments(p
)) {
344 vg_set_error(ctx
, VG_ILLEGAL_ARGUMENT_ERROR
);
349 VGfloat point
[2], normal
[2];
350 path_point(p
, startSegment
, numSegments
, distance
,
357 *tangentX
= -normal
[1];
359 *tangentY
= normal
[0];
363 void vegaPathBounds(VGPath path
,
369 struct vg_context
*ctx
= vg_current_context();
373 if (path
== VG_INVALID_HANDLE
) {
374 vg_set_error(ctx
, VG_BAD_HANDLE_ERROR
);
378 if (!minX
|| !minY
|| !width
|| !height
) {
379 vg_set_error(ctx
, VG_ILLEGAL_ARGUMENT_ERROR
);
383 if (!is_aligned(minX
) || !is_aligned(minY
) ||
384 !is_aligned(width
) || !is_aligned(height
)) {
385 vg_set_error(ctx
, VG_ILLEGAL_ARGUMENT_ERROR
);
389 p
= handle_to_path(path
);
391 caps
= path_capabilities(p
);
392 if (!(caps
& VG_PATH_CAPABILITY_PATH_BOUNDS
)) {
393 vg_set_error(ctx
, VG_PATH_CAPABILITY_ERROR
);
397 path_bounding_rect(p
, minX
, minY
, width
, height
);
400 void vegaPathTransformedBounds(VGPath path
,
406 struct vg_context
*ctx
= vg_current_context();
410 if (path
== VG_INVALID_HANDLE
) {
411 vg_set_error(ctx
, VG_BAD_HANDLE_ERROR
);
415 if (!minX
|| !minY
|| !width
|| !height
) {
416 vg_set_error(ctx
, VG_ILLEGAL_ARGUMENT_ERROR
);
420 if (!is_aligned(minX
) || !is_aligned(minY
) ||
421 !is_aligned(width
) || !is_aligned(height
)) {
422 vg_set_error(ctx
, VG_ILLEGAL_ARGUMENT_ERROR
);
426 p
= handle_to_path(path
);
428 caps
= path_capabilities(p
);
429 if (!(caps
& VG_PATH_CAPABILITY_PATH_TRANSFORMED_BOUNDS
)) {
430 vg_set_error(ctx
, VG_PATH_CAPABILITY_ERROR
);
435 /* faster, but seems to have precision problems... */
436 path_bounding_rect(p
, minX
, minY
, width
, height
);
437 if (*width
> 0 && *height
> 0) {
438 VGfloat pts
[] = {*minX
, *minY
,
439 *minX
+ *width
, *minY
,
440 *minX
+ *width
, *minY
+ *height
,
441 *minX
, *minY
+ *height
};
442 struct matrix
*matrix
= &ctx
->state
.vg
.path_user_to_surface_matrix
;
444 matrix_map_point(matrix
, pts
[0], pts
[1], pts
+ 0, pts
+ 1);
445 matrix_map_point(matrix
, pts
[2], pts
[3], pts
+ 2, pts
+ 3);
446 matrix_map_point(matrix
, pts
[4], pts
[5], pts
+ 4, pts
+ 5);
447 matrix_map_point(matrix
, pts
[6], pts
[7], pts
+ 6, pts
+ 7);
448 *minX
= MIN2(pts
[0], MIN2(pts
[2], MIN2(pts
[4], pts
[6])));
449 *minY
= MIN2(pts
[1], MIN2(pts
[3], MIN2(pts
[5], pts
[7])));
450 maxX
= MAX2(pts
[0], MAX2(pts
[2], MAX2(pts
[4], pts
[6])));
451 maxY
= MAX2(pts
[1], MAX2(pts
[3], MAX2(pts
[5], pts
[7])));
452 *width
= maxX
- *minX
;
453 *height
= maxY
- *minY
;
457 struct path
*dst
= path_create(VG_PATH_DATATYPE_F
, 1.0, 0,
458 0, 0, VG_PATH_CAPABILITY_ALL
);
459 path_transform(dst
, p
);
460 path_bounding_rect(dst
, minX
, minY
, width
, height
);
467 void vegaDrawPath(VGPath path
, VGbitfield paintModes
)
469 struct vg_context
*ctx
= vg_current_context();
470 struct path
*p
= handle_to_path(path
);
472 if (path
== VG_INVALID_HANDLE
) {
473 vg_set_error(ctx
, VG_BAD_HANDLE_ERROR
);
477 if (!(paintModes
& (VG_STROKE_PATH
| VG_FILL_PATH
))) {
478 vg_set_error(ctx
, VG_ILLEGAL_ARGUMENT_ERROR
);
482 if (path_is_empty(p
))
484 path_render(p
, paintModes
,
485 &ctx
->state
.vg
.path_user_to_surface_matrix
);