api_path.c revision d41e694cf78ada8c9258f96995115c9da8437894
190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)/**************************************************************************
290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) *
390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) * Copyright 2009 VMware, Inc.  All Rights Reserved.
490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) *
590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) * Permission is hereby granted, free of charge, to any person obtaining a
690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) * copy of this software and associated documentation files (the
790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) * "Software"), to deal in the Software without restriction, including
8f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles) * without limitation the rights to use, copy, modify, merge, publish,
990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) * distribute, sub license, and/or sell copies of the Software, and to
1090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) * permit persons to whom the Software is furnished to do so, subject to
1190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) * the following conditions:
125d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles) *
1390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) * The above copyright notice and this permission notice (including the
1490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) * next paragraph) shall be included in all copies or substantial portions
1590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) * of the Software.
1690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) *
1790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
1846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles) * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
1990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
2090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
2190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
2290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
2390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) *
2590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles) **************************************************************************/
2690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
2790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "VG/openvg.h"
2890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
2990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "vg_context.h"
3090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "handle.h"
3190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "path.h"
3290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "api.h"
3390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
3490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#include "pipe/p_context.h"
3590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
3690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)VGPath vegaCreatePath(VGint pathFormat,
3790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                      VGPathDatatype datatype,
3890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                      VGfloat scale, VGfloat bias,
3990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                      VGint segmentCapacityHint,
4090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                      VGint coordCapacityHint,
4190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                      VGbitfield capabilities)
4290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles){
4390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)   struct vg_context *ctx = vg_current_context();
4490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
4590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)   if (pathFormat != VG_PATH_FORMAT_STANDARD) {
46868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      vg_set_error(ctx, VG_UNSUPPORTED_PATH_FORMAT_ERROR);
47868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      return VG_INVALID_HANDLE;
4890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)   }
4990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)   if (datatype < VG_PATH_DATATYPE_S_8 ||
5090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)       datatype > VG_PATH_DATATYPE_F) {
5190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
5290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      return VG_INVALID_HANDLE;
53868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)   }
5490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)   if (!scale) {
5590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR);
5690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      return VG_INVALID_HANDLE;
5790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)   }
5890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
5990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)   return path_to_handle(path_create(datatype, scale, bias,
6090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                     segmentCapacityHint, coordCapacityHint,
6190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                     capabilities));
6290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
6390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
64f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles)void vegaClearPath(VGPath path, VGbitfield capabilities)
65f8ee788a64d60abd8f2d742a5fdedde054ecd910Torne (Richard Coles){
66868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)   struct vg_context *ctx = vg_current_context();
6790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)   struct path *p = 0;
6890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
6990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)   if (path == VG_INVALID_HANDLE) {
7090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
7190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      return;
7290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)   }
7390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
7490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)   p = handle_to_path(path);
7590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)   path_clear(p, capabilities);
7690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
7790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
7890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void vegaDestroyPath(VGPath p)
7990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles){
8090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)   struct path *path = 0;
8190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)   struct vg_context *ctx = vg_current_context();
8290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
8390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)   if (p == VG_INVALID_HANDLE) {
8490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
8590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      return;
8690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)   }
8790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
8846d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)   path = handle_to_path(p);
8990dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)   path_destroy(path);
9090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)}
9190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
9290dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)void vegaRemovePathCapabilities(VGPath path,
9390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)                                VGbitfield capabilities)
9490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles){
9590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)   struct vg_context *ctx = vg_current_context();
9690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)   VGbitfield current;
9790dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)   struct path *p;
9890dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)
9946d4c2bc3267f3f028f39e7e311b0f89aba2e4fdTorne (Richard Coles)   if (path == VG_INVALID_HANDLE) {
10090dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      vg_set_error(ctx, VG_BAD_HANDLE_ERROR);
10190dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)      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
110VGbitfield 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
123void 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
143void 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 (!pathData || !is_aligned_to(pathData, 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
186void 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
221void 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
241VGboolean 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
270VGfloat 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
303void 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
363void 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
400void 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
467void 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