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