api_path.c revision bf63b9d7a942bfbeef0b2b765bfc346c93de6fb7
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_LCWARC_TO_REL) {
168         vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
169         return;
170      }
171   }
172
173   p = (struct path*)dstPath;
174
175   if (!pathData || !is_aligned_to(pathData, path_datatype_size(p))) {
176      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
177      return;
178   }
179
180   if (!(path_capabilities(p)&VG_PATH_CAPABILITY_APPEND_TO)) {
181      vg_set_error(ctx, VG_PATH_CAPABILITY_ERROR);
182      return;
183   }
184
185   path_append_data(p, numSegments, pathSegments, pathData);
186}
187
188void vgModifyPathCoords(VGPath dstPath,
189                        VGint startIndex,
190                        VGint numSegments,
191                        const void * pathData)
192{
193   struct vg_context *ctx = vg_current_context();
194   struct path *p = 0;
195
196   if (dstPath == VG_INVALID_HANDLE) {
197      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
198      return;
199   }
200   if (startIndex < 0 || numSegments <= 0) {
201      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
202      return;
203   }
204
205   p = (struct path *)dstPath;
206
207   if (!pathData || !is_aligned_to(pathData, path_datatype_size(p))) {
208      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
209      return;
210   }
211
212   if (startIndex + numSegments > path_num_segments(p)) {
213      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
214      return;
215   }
216   if (!(path_capabilities(p)&VG_PATH_CAPABILITY_MODIFY)) {
217      vg_set_error(ctx, VG_PATH_CAPABILITY_ERROR);
218      return;
219   }
220   path_modify_coords(p, startIndex, numSegments, pathData);
221}
222
223void vgTransformPath(VGPath dstPath, VGPath srcPath)
224{
225   struct vg_context *ctx = vg_current_context();
226   struct path *src = 0, *dst = 0;
227
228   if (dstPath == VG_INVALID_HANDLE || srcPath == VG_INVALID_HANDLE) {
229      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
230      return;
231   }
232   src = (struct path *)srcPath;
233   dst = (struct path *)dstPath;
234
235   if (!(path_capabilities(src) & VG_PATH_CAPABILITY_TRANSFORM_FROM) ||
236       !(path_capabilities(dst) & VG_PATH_CAPABILITY_TRANSFORM_TO)) {
237      vg_set_error(ctx, VG_PATH_CAPABILITY_ERROR);
238      return;
239   }
240   path_transform(dst, src);
241}
242
243VGboolean vgInterpolatePath(VGPath dstPath,
244                            VGPath startPath,
245                            VGPath endPath,
246                            VGfloat amount)
247{
248   struct vg_context *ctx = vg_current_context();
249   struct path *start = 0, *dst = 0, *end = 0;
250
251   if (dstPath == VG_INVALID_HANDLE ||
252       startPath == VG_INVALID_HANDLE ||
253       endPath == VG_INVALID_HANDLE) {
254      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
255      return VG_FALSE;
256   }
257   dst = (struct path *)dstPath;
258   start = (struct path *)startPath;
259   end = (struct path *)endPath;
260
261   if (!(path_capabilities(dst) & VG_PATH_CAPABILITY_INTERPOLATE_TO) ||
262       !(path_capabilities(start) & VG_PATH_CAPABILITY_INTERPOLATE_FROM) ||
263       !(path_capabilities(end) & VG_PATH_CAPABILITY_INTERPOLATE_FROM)) {
264      vg_set_error(ctx, VG_PATH_CAPABILITY_ERROR);
265      return VG_FALSE;
266   }
267
268   return path_interpolate(dst,
269                           start, end, amount);
270}
271
272VGfloat vgPathLength(VGPath path,
273                     VGint startSegment,
274                     VGint numSegments)
275{
276   struct vg_context *ctx = vg_current_context();
277   struct path *p = 0;
278
279   if (path == VG_INVALID_HANDLE) {
280      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
281      return -1;
282   }
283   if (startSegment < 0) {
284      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
285      return -1;
286   }
287   if (numSegments <= 0) {
288      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
289      return -1;
290   }
291   p = (struct path*)path;
292
293   if (!(path_capabilities(p) & VG_PATH_CAPABILITY_PATH_LENGTH)) {
294      vg_set_error(ctx, VG_PATH_CAPABILITY_ERROR);
295      return -1;
296   }
297   if (startSegment + numSegments > path_num_segments(p)) {
298      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
299      return -1;
300   }
301
302   return path_length(p, startSegment, numSegments);
303}
304
305void vgPointAlongPath(VGPath path,
306                      VGint startSegment,
307                      VGint numSegments,
308                      VGfloat distance,
309                      VGfloat * x, VGfloat * y,
310                      VGfloat * tangentX,
311                      VGfloat * tangentY)
312{
313   struct vg_context *ctx = vg_current_context();
314   struct path *p = 0;
315   VGbitfield caps;
316
317   if (path == VG_INVALID_HANDLE) {
318      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
319      return;
320   }
321   if (startSegment < 0) {
322      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
323      return;
324   }
325   if (numSegments <= 0) {
326      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
327      return;
328   }
329
330   if (!is_aligned(x) || !is_aligned(y) ||
331       !is_aligned(tangentX) || !is_aligned(tangentY)) {
332      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
333      return;
334   }
335
336   p = (struct path*)path;
337
338   caps = path_capabilities(p);
339   if (!(caps & VG_PATH_CAPABILITY_POINT_ALONG_PATH) ||
340       !(caps & VG_PATH_CAPABILITY_TANGENT_ALONG_PATH)) {
341      vg_set_error(ctx, VG_PATH_CAPABILITY_ERROR);
342      return;
343   }
344
345   if (startSegment + numSegments > path_num_segments(p)) {
346      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
347      return;
348   }
349
350   {
351      VGfloat point[2], normal[2];
352      path_point(p, startSegment, numSegments, distance,
353                 point, normal);
354      if (x)
355         *x = point[0];
356      if (y)
357         *y = point[1];
358      if (tangentX)
359         *tangentX = -normal[1];
360      if (tangentY)
361         *tangentY = normal[0];
362   }
363}
364
365void vgPathBounds(VGPath path,
366                  VGfloat * minX,
367                  VGfloat * minY,
368                  VGfloat * width,
369                  VGfloat * height)
370{
371   struct vg_context *ctx = vg_current_context();
372   struct path *p = 0;
373   VGbitfield caps;
374
375   if (path == VG_INVALID_HANDLE) {
376      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
377      return;
378   }
379
380   if (!minX || !minY || !width || !height) {
381      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
382      return;
383   }
384
385   if (!is_aligned(minX) || !is_aligned(minY) ||
386       !is_aligned(width) || !is_aligned(height)) {
387      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
388      return;
389   }
390
391   p = (struct path*)path;
392
393   caps = path_capabilities(p);
394   if (!(caps & VG_PATH_CAPABILITY_PATH_BOUNDS)) {
395      vg_set_error(ctx, VG_PATH_CAPABILITY_ERROR);
396      return;
397   }
398
399   path_bounding_rect(p, minX, minY, width, height);
400}
401
402void vgPathTransformedBounds(VGPath path,
403                             VGfloat * minX,
404                             VGfloat * minY,
405                             VGfloat * width,
406                             VGfloat * height)
407{
408   struct vg_context *ctx = vg_current_context();
409   struct path *p = 0;
410   VGbitfield caps;
411
412   if (path == VG_INVALID_HANDLE) {
413      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
414      return;
415   }
416
417   if (!minX || !minY || !width || !height) {
418      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
419      return;
420   }
421
422   if (!is_aligned(minX) || !is_aligned(minY) ||
423       !is_aligned(width) || !is_aligned(height)) {
424      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
425      return;
426   }
427
428   p = (struct path*)path;
429
430   caps = path_capabilities(p);
431   if (!(caps & VG_PATH_CAPABILITY_PATH_TRANSFORMED_BOUNDS)) {
432      vg_set_error(ctx, VG_PATH_CAPABILITY_ERROR);
433      return;
434   }
435
436#if 0
437   /* faster, but seems to have precision problems... */
438   path_bounding_rect(p, minX, minY, width, height);
439   if (*width > 0 && *height > 0) {
440      VGfloat pts[] = {*minX,          *minY,
441                       *minX + *width, *minY,
442                       *minX + *width, *minY + *height,
443                       *minX,          *minY + *height};
444      struct matrix *matrix = &ctx->state.vg.path_user_to_surface_matrix;
445      VGfloat maxX, maxY;
446      matrix_map_point(matrix, pts[0], pts[1], pts + 0, pts + 1);
447      matrix_map_point(matrix, pts[2], pts[3], pts + 2, pts + 3);
448      matrix_map_point(matrix, pts[4], pts[5], pts + 4, pts + 5);
449      matrix_map_point(matrix, pts[6], pts[7], pts + 6, pts + 7);
450      *minX = MIN2(pts[0], MIN2(pts[2], MIN2(pts[4], pts[6])));
451      *minY = MIN2(pts[1], MIN2(pts[3], MIN2(pts[5], pts[7])));
452      maxX = MAX2(pts[0], MAX2(pts[2], MAX2(pts[4], pts[6])));
453      maxY = MAX2(pts[1], MAX2(pts[3], MAX2(pts[5], pts[7])));
454      *width  = maxX - *minX;
455      *height = maxY - *minY;
456   }
457#else
458   {
459      struct path *dst = path_create(VG_PATH_DATATYPE_F, 1.0, 0,
460                                     0, 0, VG_PATH_CAPABILITY_ALL);
461      path_transform(dst, p);
462      path_bounding_rect(dst, minX, minY, width, height);
463      path_destroy(dst);
464   }
465#endif
466}
467
468
469void vgDrawPath(VGPath path, VGbitfield paintModes)
470{
471   struct vg_context *ctx = vg_current_context();
472
473   if (path == VG_INVALID_HANDLE) {
474      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
475      return;
476   }
477
478   if (!(paintModes & (VG_STROKE_PATH | VG_FILL_PATH))) {
479      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
480      return;
481   }
482
483   if (path_is_empty((struct path*)path))
484      return;
485   path_render((struct path*)path, paintModes);
486}
487
488