api_path.c revision 75143ef05576ee9f25ee176bc28c3c4d03705bf5
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#include "api.h" 34 35#include "pipe/p_context.h" 36#include "util/u_inlines.h" 37#include "util/u_draw_quad.h" 38 39VGPath vegaCreatePath(VGint pathFormat, 40 VGPathDatatype datatype, 41 VGfloat scale, VGfloat bias, 42 VGint segmentCapacityHint, 43 VGint coordCapacityHint, 44 VGbitfield capabilities) 45{ 46 struct vg_context *ctx = vg_current_context(); 47 48 if (pathFormat != VG_PATH_FORMAT_STANDARD) { 49 vg_set_error(ctx, VG_UNSUPPORTED_PATH_FORMAT_ERROR); 50 return VG_INVALID_HANDLE; 51 } 52 if (datatype < VG_PATH_DATATYPE_S_8 || 53 datatype > VG_PATH_DATATYPE_F) { 54 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 55 return VG_INVALID_HANDLE; 56 } 57 if (!scale) { 58 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 59 return VG_INVALID_HANDLE; 60 } 61 62 return (VGPath)path_create(datatype, scale, bias, 63 segmentCapacityHint, coordCapacityHint, 64 capabilities); 65} 66 67void vegaClearPath(VGPath path, VGbitfield capabilities) 68{ 69 struct vg_context *ctx = vg_current_context(); 70 struct path *p = 0; 71 72 if (path == VG_INVALID_HANDLE) { 73 vg_set_error(ctx, VG_BAD_HANDLE_ERROR); 74 return; 75 } 76 77 p = (struct path *)path; 78 path_clear(p, capabilities); 79} 80 81void vegaDestroyPath(VGPath p) 82{ 83 struct path *path = 0; 84 struct vg_context *ctx = vg_current_context(); 85 86 if (p == VG_INVALID_HANDLE) { 87 vg_set_error(ctx, VG_BAD_HANDLE_ERROR); 88 return; 89 } 90 91 path = (struct path *)p; 92 path_destroy(path); 93} 94 95void vegaRemovePathCapabilities(VGPath path, 96 VGbitfield capabilities) 97{ 98 struct vg_context *ctx = vg_current_context(); 99 VGbitfield current; 100 struct path *p; 101 102 if (path == VG_INVALID_HANDLE) { 103 vg_set_error(ctx, VG_BAD_HANDLE_ERROR); 104 return; 105 } 106 107 p = (struct path*)path; 108 current = path_capabilities(p); 109 path_set_capabilities(p, (current & 110 (~(capabilities & VG_PATH_CAPABILITY_ALL)))); 111} 112 113VGbitfield vegaGetPathCapabilities(VGPath path) 114{ 115 struct vg_context *ctx = vg_current_context(); 116 struct path *p = 0; 117 118 if (path == VG_INVALID_HANDLE) { 119 vg_set_error(ctx, VG_BAD_HANDLE_ERROR); 120 return 0; 121 } 122 p = (struct path*)path; 123 return path_capabilities(p); 124} 125 126void vegaAppendPath(VGPath dstPath, VGPath srcPath) 127{ 128 struct vg_context *ctx = vg_current_context(); 129 struct path *src, *dst; 130 131 if (dstPath == VG_INVALID_HANDLE || srcPath == VG_INVALID_HANDLE) { 132 vg_set_error(ctx, VG_BAD_HANDLE_ERROR); 133 return; 134 } 135 src = (struct path *)srcPath; 136 dst = (struct path *)dstPath; 137 138 if (!(path_capabilities(src) & VG_PATH_CAPABILITY_APPEND_FROM) || 139 !(path_capabilities(dst) & VG_PATH_CAPABILITY_APPEND_TO)) { 140 vg_set_error(ctx, VG_PATH_CAPABILITY_ERROR); 141 return; 142 } 143 path_append_path(dst, src); 144} 145 146void vegaAppendPathData(VGPath dstPath, 147 VGint numSegments, 148 const VGubyte * pathSegments, 149 const void * pathData) 150{ 151 struct vg_context *ctx = vg_current_context(); 152 struct path *p = 0; 153 VGint i; 154 155 if (dstPath == VG_INVALID_HANDLE) { 156 vg_set_error(ctx, VG_BAD_HANDLE_ERROR); 157 return; 158 } 159 if (!pathSegments) { 160 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 161 return; 162 } 163 if (numSegments <= 0) { 164 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 165 return; 166 } 167 for (i = 0; i < numSegments; ++i) { 168 if (pathSegments[i] > VG_LCWARC_TO_REL) { 169 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 170 return; 171 } 172 } 173 174 p = (struct path*)dstPath; 175 176 if (!pathData || !is_aligned_to(pathData, path_datatype_size(p))) { 177 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 178 return; 179 } 180 181 if (!(path_capabilities(p)&VG_PATH_CAPABILITY_APPEND_TO)) { 182 vg_set_error(ctx, VG_PATH_CAPABILITY_ERROR); 183 return; 184 } 185 186 path_append_data(p, numSegments, pathSegments, pathData); 187} 188 189void vegaModifyPathCoords(VGPath dstPath, 190 VGint startIndex, 191 VGint numSegments, 192 const void * pathData) 193{ 194 struct vg_context *ctx = vg_current_context(); 195 struct path *p = 0; 196 197 if (dstPath == VG_INVALID_HANDLE) { 198 vg_set_error(ctx, VG_BAD_HANDLE_ERROR); 199 return; 200 } 201 if (startIndex < 0 || numSegments <= 0) { 202 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 203 return; 204 } 205 206 p = (struct path *)dstPath; 207 208 if (!pathData || !is_aligned_to(pathData, path_datatype_size(p))) { 209 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 210 return; 211 } 212 213 if (startIndex + numSegments > path_num_segments(p)) { 214 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 215 return; 216 } 217 if (!(path_capabilities(p)&VG_PATH_CAPABILITY_MODIFY)) { 218 vg_set_error(ctx, VG_PATH_CAPABILITY_ERROR); 219 return; 220 } 221 path_modify_coords(p, startIndex, numSegments, pathData); 222} 223 224void vegaTransformPath(VGPath dstPath, VGPath srcPath) 225{ 226 struct vg_context *ctx = vg_current_context(); 227 struct path *src = 0, *dst = 0; 228 229 if (dstPath == VG_INVALID_HANDLE || srcPath == VG_INVALID_HANDLE) { 230 vg_set_error(ctx, VG_BAD_HANDLE_ERROR); 231 return; 232 } 233 src = (struct path *)srcPath; 234 dst = (struct path *)dstPath; 235 236 if (!(path_capabilities(src) & VG_PATH_CAPABILITY_TRANSFORM_FROM) || 237 !(path_capabilities(dst) & VG_PATH_CAPABILITY_TRANSFORM_TO)) { 238 vg_set_error(ctx, VG_PATH_CAPABILITY_ERROR); 239 return; 240 } 241 path_transform(dst, src); 242} 243 244VGboolean vegaInterpolatePath(VGPath dstPath, 245 VGPath startPath, 246 VGPath endPath, 247 VGfloat amount) 248{ 249 struct vg_context *ctx = vg_current_context(); 250 struct path *start = 0, *dst = 0, *end = 0; 251 252 if (dstPath == VG_INVALID_HANDLE || 253 startPath == VG_INVALID_HANDLE || 254 endPath == VG_INVALID_HANDLE) { 255 vg_set_error(ctx, VG_BAD_HANDLE_ERROR); 256 return VG_FALSE; 257 } 258 dst = (struct path *)dstPath; 259 start = (struct path *)startPath; 260 end = (struct path *)endPath; 261 262 if (!(path_capabilities(dst) & VG_PATH_CAPABILITY_INTERPOLATE_TO) || 263 !(path_capabilities(start) & VG_PATH_CAPABILITY_INTERPOLATE_FROM) || 264 !(path_capabilities(end) & VG_PATH_CAPABILITY_INTERPOLATE_FROM)) { 265 vg_set_error(ctx, VG_PATH_CAPABILITY_ERROR); 266 return VG_FALSE; 267 } 268 269 return path_interpolate(dst, 270 start, end, amount); 271} 272 273VGfloat vegaPathLength(VGPath path, 274 VGint startSegment, 275 VGint numSegments) 276{ 277 struct vg_context *ctx = vg_current_context(); 278 struct path *p = 0; 279 280 if (path == VG_INVALID_HANDLE) { 281 vg_set_error(ctx, VG_BAD_HANDLE_ERROR); 282 return -1; 283 } 284 if (startSegment < 0) { 285 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 286 return -1; 287 } 288 if (numSegments <= 0) { 289 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 290 return -1; 291 } 292 p = (struct path*)path; 293 294 if (!(path_capabilities(p) & VG_PATH_CAPABILITY_PATH_LENGTH)) { 295 vg_set_error(ctx, VG_PATH_CAPABILITY_ERROR); 296 return -1; 297 } 298 if (startSegment + numSegments > path_num_segments(p)) { 299 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 300 return -1; 301 } 302 303 return path_length(p, startSegment, numSegments); 304} 305 306void vegaPointAlongPath(VGPath path, 307 VGint startSegment, 308 VGint numSegments, 309 VGfloat distance, 310 VGfloat * x, VGfloat * y, 311 VGfloat * tangentX, 312 VGfloat * tangentY) 313{ 314 struct vg_context *ctx = vg_current_context(); 315 struct path *p = 0; 316 VGbitfield caps; 317 318 if (path == VG_INVALID_HANDLE) { 319 vg_set_error(ctx, VG_BAD_HANDLE_ERROR); 320 return; 321 } 322 if (startSegment < 0) { 323 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 324 return; 325 } 326 if (numSegments <= 0) { 327 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 328 return; 329 } 330 331 if (!is_aligned(x) || !is_aligned(y) || 332 !is_aligned(tangentX) || !is_aligned(tangentY)) { 333 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 334 return; 335 } 336 337 p = (struct path*)path; 338 339 caps = path_capabilities(p); 340 if (!(caps & VG_PATH_CAPABILITY_POINT_ALONG_PATH) || 341 !(caps & VG_PATH_CAPABILITY_TANGENT_ALONG_PATH)) { 342 vg_set_error(ctx, VG_PATH_CAPABILITY_ERROR); 343 return; 344 } 345 346 if (startSegment + numSegments > path_num_segments(p)) { 347 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 348 return; 349 } 350 351 { 352 VGfloat point[2], normal[2]; 353 path_point(p, startSegment, numSegments, distance, 354 point, normal); 355 if (x) 356 *x = point[0]; 357 if (y) 358 *y = point[1]; 359 if (tangentX) 360 *tangentX = -normal[1]; 361 if (tangentY) 362 *tangentY = normal[0]; 363 } 364} 365 366void vegaPathBounds(VGPath path, 367 VGfloat * minX, 368 VGfloat * minY, 369 VGfloat * width, 370 VGfloat * height) 371{ 372 struct vg_context *ctx = vg_current_context(); 373 struct path *p = 0; 374 VGbitfield caps; 375 376 if (path == VG_INVALID_HANDLE) { 377 vg_set_error(ctx, VG_BAD_HANDLE_ERROR); 378 return; 379 } 380 381 if (!minX || !minY || !width || !height) { 382 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 383 return; 384 } 385 386 if (!is_aligned(minX) || !is_aligned(minY) || 387 !is_aligned(width) || !is_aligned(height)) { 388 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 389 return; 390 } 391 392 p = (struct path*)path; 393 394 caps = path_capabilities(p); 395 if (!(caps & VG_PATH_CAPABILITY_PATH_BOUNDS)) { 396 vg_set_error(ctx, VG_PATH_CAPABILITY_ERROR); 397 return; 398 } 399 400 path_bounding_rect(p, minX, minY, width, height); 401} 402 403void vegaPathTransformedBounds(VGPath path, 404 VGfloat * minX, 405 VGfloat * minY, 406 VGfloat * width, 407 VGfloat * height) 408{ 409 struct vg_context *ctx = vg_current_context(); 410 struct path *p = 0; 411 VGbitfield caps; 412 413 if (path == VG_INVALID_HANDLE) { 414 vg_set_error(ctx, VG_BAD_HANDLE_ERROR); 415 return; 416 } 417 418 if (!minX || !minY || !width || !height) { 419 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 420 return; 421 } 422 423 if (!is_aligned(minX) || !is_aligned(minY) || 424 !is_aligned(width) || !is_aligned(height)) { 425 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 426 return; 427 } 428 429 p = (struct path*)path; 430 431 caps = path_capabilities(p); 432 if (!(caps & VG_PATH_CAPABILITY_PATH_TRANSFORMED_BOUNDS)) { 433 vg_set_error(ctx, VG_PATH_CAPABILITY_ERROR); 434 return; 435 } 436 437#if 0 438 /* faster, but seems to have precision problems... */ 439 path_bounding_rect(p, minX, minY, width, height); 440 if (*width > 0 && *height > 0) { 441 VGfloat pts[] = {*minX, *minY, 442 *minX + *width, *minY, 443 *minX + *width, *minY + *height, 444 *minX, *minY + *height}; 445 struct matrix *matrix = &ctx->state.vg.path_user_to_surface_matrix; 446 VGfloat maxX, maxY; 447 matrix_map_point(matrix, pts[0], pts[1], pts + 0, pts + 1); 448 matrix_map_point(matrix, pts[2], pts[3], pts + 2, pts + 3); 449 matrix_map_point(matrix, pts[4], pts[5], pts + 4, pts + 5); 450 matrix_map_point(matrix, pts[6], pts[7], pts + 6, pts + 7); 451 *minX = MIN2(pts[0], MIN2(pts[2], MIN2(pts[4], pts[6]))); 452 *minY = MIN2(pts[1], MIN2(pts[3], MIN2(pts[5], pts[7]))); 453 maxX = MAX2(pts[0], MAX2(pts[2], MAX2(pts[4], pts[6]))); 454 maxY = MAX2(pts[1], MAX2(pts[3], MAX2(pts[5], pts[7]))); 455 *width = maxX - *minX; 456 *height = maxY - *minY; 457 } 458#else 459 { 460 struct path *dst = path_create(VG_PATH_DATATYPE_F, 1.0, 0, 461 0, 0, VG_PATH_CAPABILITY_ALL); 462 path_transform(dst, p); 463 path_bounding_rect(dst, minX, minY, width, height); 464 path_destroy(dst); 465 } 466#endif 467} 468 469 470void vegaDrawPath(VGPath path, VGbitfield paintModes) 471{ 472 struct vg_context *ctx = vg_current_context(); 473 474 if (path == VG_INVALID_HANDLE) { 475 vg_set_error(ctx, VG_BAD_HANDLE_ERROR); 476 return; 477 } 478 479 if (!(paintModes & (VG_STROKE_PATH | VG_FILL_PATH))) { 480 vg_set_error(ctx, VG_ILLEGAL_ARGUMENT_ERROR); 481 return; 482 } 483 484 if (path_is_empty((struct path*)path)) 485 return; 486 path_render((struct path*)path, paintModes); 487} 488 489