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