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 488