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