1 /**************************************************************************
2 *
3 * Copyright 2009 VMware, Inc. All Rights Reserved.
4 *
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:
12 *
13 * The above copyright notice and this permission notice (including the
14 * next paragraph) shall be included in all copies or substantial portions
15 * of the Software.
16 *
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.
24 *
25 **************************************************************************/
26
27 #include "VG/openvg.h"
28
29 #include "vg_context.h"
30 #include "handle.h"
31 #include "path.h"
32 #include "api.h"
33
34 #include "pipe/p_context.h"
35
vegaCreatePath(VGint pathFormat,VGPathDatatype datatype,VGfloat scale,VGfloat bias,VGint segmentCapacityHint,VGint coordCapacityHint,VGbitfield capabilities)36 VGPath vegaCreatePath(VGint pathFormat,
37 VGPathDatatype datatype,
38 VGfloat scale, VGfloat bias,
39 VGint segmentCapacityHint,
40 VGint coordCapacityHint,
41 VGbitfield capabilities)
42 {
43 struct vg_context *ctx = vg_current_context();
44
45 if (pathFormat != VG_PATH_FORMAT_STANDARD) {
46 vg_set_error(ctx, VG_UNSUPPORTED_PATH_FORMAT_ERROR);
47 return VG_INVALID_HANDLE;
48 }
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;
53 }
54 if (!scale) {
55 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
56 return VG_INVALID_HANDLE;
57 }
58
59 return path_to_handle(path_create(datatype, scale, bias,
60 segmentCapacityHint, coordCapacityHint,
61 capabilities));
62 }
63
vegaClearPath(VGPath path,VGbitfield capabilities)64 void vegaClearPath(VGPath path, VGbitfield capabilities)
65 {
66 struct vg_context *ctx = vg_current_context();
67 struct path *p = 0;
68
69 if (path == VG_INVALID_HANDLE) {
70 vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
71 return;
72 }
73
74 p = handle_to_path(path);
75 path_clear(p, capabilities);
76 }
77
vegaDestroyPath(VGPath p)78 void vegaDestroyPath(VGPath p)
79 {
80 struct path *path = 0;
81 struct vg_context *ctx = vg_current_context();
82
83 if (p == VG_INVALID_HANDLE) {
84 vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
85 return;
86 }
87
88 path = handle_to_path(p);
89 path_destroy(path);
90 }
91
vegaRemovePathCapabilities(VGPath path,VGbitfield capabilities)92 void vegaRemovePathCapabilities(VGPath path,
93 VGbitfield capabilities)
94 {
95 struct vg_context *ctx = vg_current_context();
96 VGbitfield current;
97 struct path *p;
98
99 if (path == VG_INVALID_HANDLE) {
100 vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
101 return;
102 }
103
104 p = handle_to_path(path);
105 current = path_capabilities(p);
106 path_set_capabilities(p, (current &
107 (~(capabilities & VG_PATH_CAPABILITY_ALL))));
108 }
109
vegaGetPathCapabilities(VGPath path)110 VGbitfield vegaGetPathCapabilities(VGPath path)
111 {
112 struct vg_context *ctx = vg_current_context();
113 struct path *p = 0;
114
115 if (path == VG_INVALID_HANDLE) {
116 vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
117 return 0;
118 }
119 p = handle_to_path(path);
120 return path_capabilities(p);
121 }
122
vegaAppendPath(VGPath dstPath,VGPath srcPath)123 void vegaAppendPath(VGPath dstPath, VGPath srcPath)
124 {
125 struct vg_context *ctx = vg_current_context();
126 struct path *src, *dst;
127
128 if (dstPath == VG_INVALID_HANDLE || srcPath == VG_INVALID_HANDLE) {
129 vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
130 return;
131 }
132 src = handle_to_path(srcPath);
133 dst = handle_to_path(dstPath);
134
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);
138 return;
139 }
140 path_append_path(dst, src);
141 }
142
vegaAppendPathData(VGPath dstPath,VGint numSegments,const VGubyte * pathSegments,const void * pathData)143 void vegaAppendPathData(VGPath dstPath,
144 VGint numSegments,
145 const VGubyte * pathSegments,
146 const void * pathData)
147 {
148 struct vg_context *ctx = vg_current_context();
149 struct path *p = 0;
150 VGint i;
151
152 if (dstPath == VG_INVALID_HANDLE) {
153 vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
154 return;
155 }
156 if (!pathSegments) {
157 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
158 return;
159 }
160 if (numSegments <= 0) {
161 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
162 return;
163 }
164 for (i = 0; i < numSegments; ++i) {
165 if (pathSegments[i] > VG_LCWARC_TO_REL) {
166 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
167 return;
168 }
169 }
170
171 p = handle_to_path(dstPath);
172
173 if (!p || !is_aligned_to(p, path_datatype_size(p))) {
174 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
175 return;
176 }
177
178 if (!(path_capabilities(p)&VG_PATH_CAPABILITY_APPEND_TO)) {
179 vg_set_error(ctx, VG_PATH_CAPABILITY_ERROR);
180 return;
181 }
182
183 path_append_data(p, numSegments, pathSegments, pathData);
184 }
185
vegaModifyPathCoords(VGPath dstPath,VGint startIndex,VGint numSegments,const void * pathData)186 void vegaModifyPathCoords(VGPath dstPath,
187 VGint startIndex,
188 VGint numSegments,
189 const void * pathData)
190 {
191 struct vg_context *ctx = vg_current_context();
192 struct path *p = 0;
193
194 if (dstPath == VG_INVALID_HANDLE) {
195 vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
196 return;
197 }
198 if (startIndex < 0 || numSegments <= 0) {
199 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
200 return;
201 }
202
203 p = handle_to_path(dstPath);
204
205 if (!pathData || !is_aligned_to(pathData, path_datatype_size(p))) {
206 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
207 return;
208 }
209
210 if (startIndex + numSegments > path_num_segments(p)) {
211 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
212 return;
213 }
214 if (!(path_capabilities(p)&VG_PATH_CAPABILITY_MODIFY)) {
215 vg_set_error(ctx, VG_PATH_CAPABILITY_ERROR);
216 return;
217 }
218 path_modify_coords(p, startIndex, numSegments, pathData);
219 }
220
vegaTransformPath(VGPath dstPath,VGPath srcPath)221 void vegaTransformPath(VGPath dstPath, VGPath srcPath)
222 {
223 struct vg_context *ctx = vg_current_context();
224 struct path *src = 0, *dst = 0;
225
226 if (dstPath == VG_INVALID_HANDLE || srcPath == VG_INVALID_HANDLE) {
227 vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
228 return;
229 }
230 src = handle_to_path(srcPath);
231 dst = handle_to_path(dstPath);
232
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);
236 return;
237 }
238 path_transform(dst, src);
239 }
240
vegaInterpolatePath(VGPath dstPath,VGPath startPath,VGPath endPath,VGfloat amount)241 VGboolean vegaInterpolatePath(VGPath dstPath,
242 VGPath startPath,
243 VGPath endPath,
244 VGfloat amount)
245 {
246 struct vg_context *ctx = vg_current_context();
247 struct path *start = 0, *dst = 0, *end = 0;
248
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);
253 return VG_FALSE;
254 }
255 dst = handle_to_path(dstPath);
256 start = handle_to_path(startPath);
257 end = handle_to_path(endPath);
258
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);
263 return VG_FALSE;
264 }
265
266 return path_interpolate(dst,
267 start, end, amount);
268 }
269
vegaPathLength(VGPath path,VGint startSegment,VGint numSegments)270 VGfloat vegaPathLength(VGPath path,
271 VGint startSegment,
272 VGint numSegments)
273 {
274 struct vg_context *ctx = vg_current_context();
275 struct path *p = 0;
276
277 if (path == VG_INVALID_HANDLE) {
278 vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
279 return -1;
280 }
281 if (startSegment < 0) {
282 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
283 return -1;
284 }
285 if (numSegments <= 0) {
286 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
287 return -1;
288 }
289 p = handle_to_path(path);
290
291 if (!(path_capabilities(p) & VG_PATH_CAPABILITY_PATH_LENGTH)) {
292 vg_set_error(ctx, VG_PATH_CAPABILITY_ERROR);
293 return -1;
294 }
295 if (startSegment + numSegments > path_num_segments(p)) {
296 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
297 return -1;
298 }
299
300 return path_length(p, startSegment, numSegments);
301 }
302
vegaPointAlongPath(VGPath path,VGint startSegment,VGint numSegments,VGfloat distance,VGfloat * x,VGfloat * y,VGfloat * tangentX,VGfloat * tangentY)303 void vegaPointAlongPath(VGPath path,
304 VGint startSegment,
305 VGint numSegments,
306 VGfloat distance,
307 VGfloat * x, VGfloat * y,
308 VGfloat * tangentX,
309 VGfloat * tangentY)
310 {
311 struct vg_context *ctx = vg_current_context();
312 struct path *p = 0;
313 VGbitfield caps;
314
315 if (path == VG_INVALID_HANDLE) {
316 vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
317 return;
318 }
319 if (startSegment < 0) {
320 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
321 return;
322 }
323 if (numSegments <= 0) {
324 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
325 return;
326 }
327
328 if (!is_aligned(x) || !is_aligned(y) ||
329 !is_aligned(tangentX) || !is_aligned(tangentY)) {
330 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
331 return;
332 }
333
334 p = handle_to_path(path);
335
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);
340 return;
341 }
342
343 if (startSegment + numSegments > path_num_segments(p)) {
344 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
345 return;
346 }
347
348 {
349 VGfloat point[2], normal[2];
350 path_point(p, startSegment, numSegments, distance,
351 point, normal);
352 if (x)
353 *x = point[0];
354 if (y)
355 *y = point[1];
356 if (tangentX)
357 *tangentX = -normal[1];
358 if (tangentY)
359 *tangentY = normal[0];
360 }
361 }
362
vegaPathBounds(VGPath path,VGfloat * minX,VGfloat * minY,VGfloat * width,VGfloat * height)363 void vegaPathBounds(VGPath path,
364 VGfloat * minX,
365 VGfloat * minY,
366 VGfloat * width,
367 VGfloat * height)
368 {
369 struct vg_context *ctx = vg_current_context();
370 struct path *p = 0;
371 VGbitfield caps;
372
373 if (path == VG_INVALID_HANDLE) {
374 vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
375 return;
376 }
377
378 if (!minX || !minY || !width || !height) {
379 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
380 return;
381 }
382
383 if (!is_aligned(minX) || !is_aligned(minY) ||
384 !is_aligned(width) || !is_aligned(height)) {
385 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
386 return;
387 }
388
389 p = handle_to_path(path);
390
391 caps = path_capabilities(p);
392 if (!(caps & VG_PATH_CAPABILITY_PATH_BOUNDS)) {
393 vg_set_error(ctx, VG_PATH_CAPABILITY_ERROR);
394 return;
395 }
396
397 path_bounding_rect(p, minX, minY, width, height);
398 }
399
vegaPathTransformedBounds(VGPath path,VGfloat * minX,VGfloat * minY,VGfloat * width,VGfloat * height)400 void vegaPathTransformedBounds(VGPath path,
401 VGfloat * minX,
402 VGfloat * minY,
403 VGfloat * width,
404 VGfloat * height)
405 {
406 struct vg_context *ctx = vg_current_context();
407 struct path *p = 0;
408 VGbitfield caps;
409
410 if (path == VG_INVALID_HANDLE) {
411 vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
412 return;
413 }
414
415 if (!minX || !minY || !width || !height) {
416 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
417 return;
418 }
419
420 if (!is_aligned(minX) || !is_aligned(minY) ||
421 !is_aligned(width) || !is_aligned(height)) {
422 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
423 return;
424 }
425
426 p = handle_to_path(path);
427
428 caps = path_capabilities(p);
429 if (!(caps & VG_PATH_CAPABILITY_PATH_TRANSFORMED_BOUNDS)) {
430 vg_set_error(ctx, VG_PATH_CAPABILITY_ERROR);
431 return;
432 }
433
434 #if 0
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;
443 VGfloat maxX, maxY;
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;
454 }
455 #else
456 {
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);
461 path_destroy(dst);
462 }
463 #endif
464 }
465
466
vegaDrawPath(VGPath path,VGbitfield paintModes)467 void vegaDrawPath(VGPath path, VGbitfield paintModes)
468 {
469 struct vg_context *ctx = vg_current_context();
470 struct path *p = handle_to_path(path);
471
472 if (path == VG_INVALID_HANDLE) {
473 vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
474 return;
475 }
476
477 if (!(paintModes & (VG_STROKE_PATH | VG_FILL_PATH))) {
478 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
479 return;
480 }
481
482 if (path_is_empty(p))
483 return;
484 path_render(p, paintModes,
485 &ctx->state.vg.path_user_to_surface_matrix);
486 }
487
488