Details | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
4358 | Serge | 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 "handle.h" |
||
31 | #include "path.h" |
||
32 | #include "api.h" |
||
33 | |||
34 | #include "pipe/p_context.h" |
||
35 | |||
36 | VGPath vegaCreatePath(VGint pathFormat, |
||
37 | VGPathDatatype datatype, |
||
38 | VGfloat scale, VGfloat bias, |
||
39 | VGint segmentCapacityHint, |
||
40 | VGint coordCapacityHint, |
||
41 | VGbitfield capabilities) |
||
42 | { |
||
43 | struct vg_context *ctx = vg_current_context(); |
||
44 | |||
45 | if (pathFormat != VG_PATH_FORMAT_STANDARD) { |
||
46 | vg_set_error(ctx, VG_UNSUPPORTED_PATH_FORMAT_ERROR); |
||
47 | return VG_INVALID_HANDLE; |
||
48 | } |
||
49 | if (datatype < VG_PATH_DATATYPE_S_8 || |
||
50 | datatype > VG_PATH_DATATYPE_F) { |
||
51 | vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); |
||
52 | return VG_INVALID_HANDLE; |
||
53 | } |
||
54 | if (!scale) { |
||
55 | vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); |
||
56 | return VG_INVALID_HANDLE; |
||
57 | } |
||
58 | |||
59 | return path_to_handle(path_create(datatype, scale, bias, |
||
60 | segmentCapacityHint, coordCapacityHint, |
||
61 | capabilities)); |
||
62 | } |
||
63 | |||
64 | void vegaClearPath(VGPath path, VGbitfield capabilities) |
||
65 | { |
||
66 | struct vg_context *ctx = vg_current_context(); |
||
67 | struct path *p = 0; |
||
68 | |||
69 | if (path == VG_INVALID_HANDLE) { |
||
70 | vg_set_error(ctx, VG_BAD_HANDLE_ERROR); |
||
71 | return; |
||
72 | } |
||
73 | |||
74 | p = handle_to_path(path); |
||
75 | path_clear(p, capabilities); |
||
76 | } |
||
77 | |||
78 | void vegaDestroyPath(VGPath p) |
||
79 | { |
||
80 | struct path *path = 0; |
||
81 | struct vg_context *ctx = vg_current_context(); |
||
82 | |||
83 | if (p == VG_INVALID_HANDLE) { |
||
84 | vg_set_error(ctx, VG_BAD_HANDLE_ERROR); |
||
85 | return; |
||
86 | } |
||
87 | |||
88 | path = handle_to_path(p); |
||
89 | path_destroy(path); |
||
90 | } |
||
91 | |||
92 | void vegaRemovePathCapabilities(VGPath path, |
||
93 | VGbitfield capabilities) |
||
94 | { |
||
95 | struct vg_context *ctx = vg_current_context(); |
||
96 | VGbitfield current; |
||
97 | struct path *p; |
||
98 | |||
99 | if (path == VG_INVALID_HANDLE) { |
||
100 | vg_set_error(ctx, VG_BAD_HANDLE_ERROR); |
||
101 | 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 | |||
110 | VGbitfield 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 | |||
123 | void 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 | |||
143 | void 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 (!p || !is_aligned_to(p, 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 | |||
186 | void 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 | |||
221 | void 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 | |||
241 | VGboolean 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 | |||
270 | VGfloat 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 | |||
303 | void 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 | |||
363 | void 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 | |||
400 | void 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 | |||
467 | void 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 |