api_path.c revision 75143ef05576ee9f25ee176bc28c3c4d03705bf5
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#include "api.h"
34
35#include "pipe/p_context.h"
36#include "util/u_inlines.h"
37#include "util/u_draw_quad.h"
38
39VGPath vegaCreatePath(VGint pathFormat,
40                      VGPathDatatype datatype,
41                      VGfloat scale, VGfloat bias,
42                      VGint segmentCapacityHint,
43                      VGint coordCapacityHint,
44                      VGbitfield capabilities)
45{
46   struct vg_context *ctx = vg_current_context();
47
48   if (pathFormat != VG_PATH_FORMAT_STANDARD) {
49      vg_set_error(ctx, VG_UNSUPPORTED_PATH_FORMAT_ERROR);
50      return VG_INVALID_HANDLE;
51   }
52   if (datatype < VG_PATH_DATATYPE_S_8 ||
53       datatype > VG_PATH_DATATYPE_F) {
54      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
55      return VG_INVALID_HANDLE;
56   }
57   if (!scale) {
58      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
59      return VG_INVALID_HANDLE;
60   }
61
62   return (VGPath)path_create(datatype, scale, bias,
63                              segmentCapacityHint, coordCapacityHint,
64                              capabilities);
65}
66
67void vegaClearPath(VGPath path, VGbitfield capabilities)
68{
69   struct vg_context *ctx = vg_current_context();
70   struct path *p = 0;
71
72   if (path == VG_INVALID_HANDLE) {
73      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
74      return;
75   }
76
77   p = (struct path *)path;
78   path_clear(p, capabilities);
79}
80
81void vegaDestroyPath(VGPath p)
82{
83   struct path *path = 0;
84   struct vg_context *ctx = vg_current_context();
85
86   if (p == VG_INVALID_HANDLE) {
87      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
88      return;
89   }
90
91   path = (struct path *)p;
92   path_destroy(path);
93}
94
95void vegaRemovePathCapabilities(VGPath path,
96                                VGbitfield capabilities)
97{
98   struct vg_context *ctx = vg_current_context();
99   VGbitfield current;
100   struct path *p;
101
102   if (path == VG_INVALID_HANDLE) {
103      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
104      return;
105   }
106
107   p = (struct path*)path;
108   current = path_capabilities(p);
109   path_set_capabilities(p, (current &
110                             (~(capabilities & VG_PATH_CAPABILITY_ALL))));
111}
112
113VGbitfield vegaGetPathCapabilities(VGPath path)
114{
115   struct vg_context *ctx = vg_current_context();
116   struct path *p = 0;
117
118   if (path == VG_INVALID_HANDLE) {
119      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
120      return 0;
121   }
122   p = (struct path*)path;
123   return path_capabilities(p);
124}
125
126void vegaAppendPath(VGPath dstPath, VGPath srcPath)
127{
128   struct vg_context *ctx = vg_current_context();
129   struct path *src, *dst;
130
131   if (dstPath == VG_INVALID_HANDLE || srcPath == VG_INVALID_HANDLE) {
132      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
133      return;
134   }
135   src = (struct path *)srcPath;
136   dst = (struct path *)dstPath;
137
138   if (!(path_capabilities(src) & VG_PATH_CAPABILITY_APPEND_FROM) ||
139       !(path_capabilities(dst) & VG_PATH_CAPABILITY_APPEND_TO)) {
140      vg_set_error(ctx, VG_PATH_CAPABILITY_ERROR);
141      return;
142   }
143   path_append_path(dst, src);
144}
145
146void vegaAppendPathData(VGPath dstPath,
147                        VGint numSegments,
148                        const VGubyte * pathSegments,
149                        const void * pathData)
150{
151   struct vg_context *ctx = vg_current_context();
152   struct path *p = 0;
153   VGint i;
154
155   if (dstPath == VG_INVALID_HANDLE) {
156      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
157      return;
158   }
159   if (!pathSegments) {
160      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
161      return;
162   }
163   if (numSegments <= 0) {
164      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
165      return;
166   }
167   for (i = 0; i < numSegments; ++i) {
168      if (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 vegaModifyPathCoords(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 vegaTransformPath(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 vegaInterpolatePath(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 vegaPathLength(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 vegaPointAlongPath(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 vegaPathBounds(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 vegaPathTransformedBounds(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 vegaDrawPath(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