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