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 "path.h" 28 29#include "stroker.h" 30#include "polygon.h" 31#include "bezier.h" 32#include "matrix.h" 33#include "vg_context.h" 34#include "util_array.h" 35#include "arc.h" 36#include "path_utils.h" 37#include "paint.h" 38#include "shader.h" 39 40#include "util/u_memory.h" 41 42#include <assert.h> 43 44#define DEBUG_PATH 0 45 46struct path { 47 struct vg_object base; 48 VGbitfield caps; 49 VGboolean dirty; 50 VGboolean dirty_stroke; 51 52 VGPathDatatype datatype; 53 54 VGfloat scale; 55 VGfloat bias; 56 57 VGint num_segments; 58 59 struct array * segments; 60 struct array * control_points; 61 62 struct { 63 struct polygon_array polygon_array; 64 struct matrix matrix; 65 } fill_polys; 66 67 struct { 68 struct path *path; 69 struct matrix matrix; 70 VGfloat stroke_width; 71 VGfloat miter_limit; 72 VGCapStyle cap_style; 73 VGJoinStyle join_style; 74 } stroked; 75}; 76 77 78static INLINE void data_at(void **data, 79 struct path *p, 80 VGint start, VGint count, 81 VGfloat *out) 82{ 83 VGPathDatatype dt = p->datatype; 84 VGint i; 85 VGint end = start + count; 86 VGfloat *itr = out; 87 88 switch(dt) { 89 case VG_PATH_DATATYPE_S_8: { 90 VGbyte **bdata = (VGbyte **)data; 91 for (i = start; i < end; ++i) { 92 *itr = (*bdata)[i]; 93 ++itr; 94 } 95 *bdata += count; 96 } 97 break; 98 case VG_PATH_DATATYPE_S_16: { 99 VGshort **bdata = (VGshort **)data; 100 for (i = start; i < end; ++i) { 101 *itr = (*bdata)[i]; 102 ++itr; 103 } 104 *bdata += count; 105 } 106 break; 107 case VG_PATH_DATATYPE_S_32: { 108 VGint **bdata = (VGint **)data; 109 for (i = start; i < end; ++i) { 110 *itr = (*bdata)[i]; 111 ++itr; 112 } 113 *bdata += count; 114 } 115 break; 116 case VG_PATH_DATATYPE_F: { 117 VGfloat **fdata = (VGfloat **)data; 118 for (i = start; i < end; ++i) { 119 *itr = (*fdata)[i]; 120 ++itr; 121 } 122 *fdata += count; 123 } 124 break; 125 default: 126 debug_assert(!"Unknown path datatype!"); 127 } 128} 129 130 131void vg_float_to_datatype(VGPathDatatype datatype, 132 VGubyte *common_data, 133 const VGfloat *data, 134 VGint num_coords) 135{ 136 VGint i; 137 switch(datatype) { 138 case VG_PATH_DATATYPE_S_8: { 139 for (i = 0; i < num_coords; ++i) { 140 common_data[i] = (VGubyte)data[i]; 141 } 142 } 143 break; 144 case VG_PATH_DATATYPE_S_16: { 145 VGshort *buf = (VGshort*)common_data; 146 for (i = 0; i < num_coords; ++i) { 147 buf[i] = (VGshort)data[i]; 148 } 149 } 150 break; 151 case VG_PATH_DATATYPE_S_32: { 152 VGint *buf = (VGint*)common_data; 153 for (i = 0; i < num_coords; ++i) { 154 buf[i] = (VGint)data[i]; 155 } 156 } 157 break; 158 case VG_PATH_DATATYPE_F: { 159 memcpy(common_data, data, sizeof(VGfloat) * num_coords); 160 } 161 break; 162 default: 163 debug_assert(!"Unknown path datatype!"); 164 } 165} 166 167static void coords_adjust_by_scale_bias(struct path *p, 168 void *pdata, VGint num_coords, 169 VGfloat scale, VGfloat bias, 170 VGPathDatatype datatype) 171{ 172 VGfloat data[8]; 173 void *coords = (VGfloat *)pdata; 174 VGubyte *common_data = (VGubyte *)pdata; 175 VGint size_dst = size_for_datatype(datatype); 176 VGint i; 177 178 for (i = 0; i < num_coords; ++i) { 179 data_at(&coords, p, 0, 1, data); 180 data[0] = data[0] * scale + bias; 181 vg_float_to_datatype(datatype, common_data, data, 1); 182 common_data += size_dst; 183 } 184} 185 186struct path * path_create(VGPathDatatype dt, VGfloat scale, VGfloat bias, 187 VGint segmentCapacityHint, 188 VGint coordCapacityHint, 189 VGbitfield capabilities) 190{ 191 struct path *path = CALLOC_STRUCT(path); 192 193 vg_init_object(&path->base, vg_current_context(), VG_OBJECT_PATH); 194 path->caps = capabilities & VG_PATH_CAPABILITY_ALL; 195 vg_context_add_object(vg_current_context(), &path->base); 196 197 path->datatype = dt; 198 path->scale = scale; 199 path->bias = bias; 200 201 path->segments = array_create(size_for_datatype(VG_PATH_DATATYPE_S_8)); 202 path->control_points = array_create(size_for_datatype(dt)); 203 204 path->dirty = VG_TRUE; 205 path->dirty_stroke = VG_TRUE; 206 207 return path; 208} 209 210static void polygon_array_cleanup(struct polygon_array *polyarray) 211{ 212 if (polyarray->array) { 213 VGint i; 214 215 for (i = 0; i < polyarray->array->num_elements; i++) { 216 struct polygon *p = ((struct polygon **) polyarray->array->data)[i]; 217 polygon_destroy(p); 218 } 219 220 array_destroy(polyarray->array); 221 polyarray->array = NULL; 222 } 223} 224 225void path_destroy(struct path *p) 226{ 227 vg_context_remove_object(vg_current_context(), &p->base); 228 229 array_destroy(p->segments); 230 array_destroy(p->control_points); 231 232 polygon_array_cleanup(&p->fill_polys.polygon_array); 233 234 if (p->stroked.path) 235 path_destroy(p->stroked.path); 236 237 FREE(p); 238} 239 240VGbitfield path_capabilities(struct path *p) 241{ 242 return p->caps; 243} 244 245void path_set_capabilities(struct path *p, VGbitfield bf) 246{ 247 p->caps = (bf & VG_PATH_CAPABILITY_ALL); 248} 249 250void path_append_data(struct path *p, 251 VGint numSegments, 252 const VGubyte * pathSegments, 253 const void * pathData) 254{ 255 VGint old_segments = p->num_segments; 256 VGint num_new_coords = num_elements_for_segments(pathSegments, numSegments); 257 array_append_data(p->segments, pathSegments, numSegments); 258 array_append_data(p->control_points, pathData, num_new_coords); 259 260 p->num_segments += numSegments; 261 if (!floatsEqual(p->scale, 1.f) || !floatsEqual(p->bias, 0.f)) { 262 VGubyte *coords = (VGubyte*)p->control_points->data; 263 coords_adjust_by_scale_bias(p, 264 coords + old_segments * p->control_points->datatype_size, 265 num_new_coords, 266 p->scale, p->bias, p->datatype); 267 } 268 p->dirty = VG_TRUE; 269 p->dirty_stroke = VG_TRUE; 270} 271 272VGint path_num_segments(struct path *p) 273{ 274 return p->num_segments; 275} 276 277static INLINE void map_if_relative(VGfloat ox, VGfloat oy, 278 VGboolean relative, 279 VGfloat *x, VGfloat *y) 280{ 281 if (relative) { 282 if (x) 283 *x += ox; 284 if (y) 285 *y += oy; 286 } 287} 288 289static INLINE void close_polygon(struct polygon *current, 290 VGfloat sx, VGfloat sy, 291 VGfloat ox, VGfloat oy, 292 struct matrix *matrix) 293{ 294 if (!floatsEqual(sx, ox) || 295 !floatsEqual(sy, oy)) { 296 VGfloat x0 = sx; 297 VGfloat y0 = sy; 298 matrix_map_point(matrix, x0, y0, &x0, &y0); 299 polygon_vertex_append(current, x0, y0); 300 } 301} 302 303static void convert_path(struct path *p, 304 VGPathDatatype to, 305 void *dst, 306 VGint num_coords) 307{ 308 VGfloat data[8]; 309 void *coords = (VGfloat *)p->control_points->data; 310 VGubyte *common_data = (VGubyte *)dst; 311 VGint size_dst = size_for_datatype(to); 312 VGint i; 313 314 for (i = 0; i < num_coords; ++i) { 315 data_at(&coords, p, 0, 1, data); 316 vg_float_to_datatype(to, common_data, data, 1); 317 common_data += size_dst; 318 } 319} 320 321static void polygon_array_calculate_bounds( struct polygon_array *polyarray ) 322{ 323 struct array *polys = polyarray->array; 324 VGfloat min_x, max_x; 325 VGfloat min_y, max_y; 326 VGfloat bounds[4]; 327 unsigned i; 328 329 assert(polys); 330 331 if (!polys->num_elements) { 332 polyarray->min_x = 0.0f; 333 polyarray->min_y = 0.0f; 334 polyarray->max_x = 0.0f; 335 polyarray->max_y = 0.0f; 336 return; 337 } 338 339 polygon_bounding_rect((((struct polygon**)polys->data)[0]), bounds); 340 min_x = bounds[0]; 341 min_y = bounds[1]; 342 max_x = bounds[0] + bounds[2]; 343 max_y = bounds[1] + bounds[3]; 344 for (i = 1; i < polys->num_elements; ++i) { 345 struct polygon *p = (((struct polygon**)polys->data)[i]); 346 polygon_bounding_rect(p, bounds); 347 min_x = MIN2(min_x, bounds[0]); 348 min_y = MIN2(min_y, bounds[1]); 349 max_x = MAX2(max_x, bounds[0] + bounds[2]); 350 max_y = MAX2(max_y, bounds[1] + bounds[3]); 351 } 352 353 polyarray->min_x = min_x; 354 polyarray->min_y = min_y; 355 polyarray->max_x = max_x; 356 polyarray->max_y = max_y; 357} 358 359 360static struct polygon_array * path_get_fill_polygons(struct path *p, struct matrix *matrix) 361{ 362 VGint i; 363 struct polygon *current = 0; 364 VGfloat sx, sy, px, py, ox, oy; 365 VGfloat x0, y0, x1, y1, x2, y2, x3, y3; 366 VGfloat data[8]; 367 void *coords = (VGfloat *)p->control_points->data; 368 struct array *array; 369 370 memset(data, 0, sizeof(data)); 371 372 if (p->fill_polys.polygon_array.array) 373 { 374 if (memcmp( &p->fill_polys.matrix, 375 matrix, 376 sizeof *matrix ) == 0 && p->dirty == VG_FALSE) 377 { 378 return &p->fill_polys.polygon_array; 379 } 380 else { 381 polygon_array_cleanup(&p->fill_polys.polygon_array); 382 } 383 } 384 385 /* an array of pointers to polygons */ 386 array = array_create(sizeof(struct polygon *)); 387 388 sx = sy = px = py = ox = oy = 0.f; 389 390 if (p->num_segments) 391 current = polygon_create(32); 392 393 for (i = 0; i < p->num_segments; ++i) { 394 VGubyte segment = ((VGubyte*)(p->segments->data))[i]; 395 VGint command = SEGMENT_COMMAND(segment); 396 VGboolean relative = SEGMENT_ABS_REL(segment); 397 398 switch(command) { 399 case VG_CLOSE_PATH: 400 close_polygon(current, sx, sy, ox, oy, matrix); 401 ox = sx; 402 oy = sy; 403 break; 404 case VG_MOVE_TO: 405 if (current && polygon_vertex_count(current) > 0) { 406 /* add polygon */ 407 close_polygon(current, sx, sy, ox, oy, matrix); 408 array_append_data(array, ¤t, 1); 409 current = polygon_create(32); 410 } 411 data_at(&coords, p, 0, 2, data); 412 x0 = data[0]; 413 y0 = data[1]; 414 map_if_relative(ox, oy, relative, &x0, &y0); 415 sx = x0; 416 sy = y0; 417 ox = x0; 418 oy = y0; 419 px = x0; 420 py = y0; 421 matrix_map_point(matrix, x0, y0, &x0, &y0); 422 polygon_vertex_append(current, x0, y0); 423 break; 424 case VG_LINE_TO: 425 data_at(&coords, p, 0, 2, data); 426 x0 = data[0]; 427 y0 = data[1]; 428 map_if_relative(ox, oy, relative, &x0, &y0); 429 ox = x0; 430 oy = y0; 431 px = x0; 432 py = y0; 433 matrix_map_point(matrix, x0, y0, &x0, &y0); 434 polygon_vertex_append(current, x0, y0); 435 break; 436 case VG_HLINE_TO: 437 data_at(&coords, p, 0, 1, data); 438 x0 = data[0]; 439 y0 = oy; 440 map_if_relative(ox, oy, relative, &x0, 0); 441 ox = x0; 442 px = x0; 443 py = y0; 444 matrix_map_point(matrix, x0, y0, &x0, &y0); 445 polygon_vertex_append(current, x0, y0); 446 break; 447 case VG_VLINE_TO: 448 data_at(&coords, p, 0, 1, data); 449 x0 = ox; 450 y0 = data[0]; 451 map_if_relative(ox, oy, relative, 0, &y0); 452 oy = y0; 453 px = x0; 454 py = y0; 455 matrix_map_point(matrix, x0, y0, &x0, &y0); 456 polygon_vertex_append(current, x0, y0); 457 break; 458 case VG_CUBIC_TO: { 459 struct bezier bezier; 460 data_at(&coords, p, 0, 6, data); 461 x0 = ox; 462 y0 = oy; 463 x1 = data[0]; 464 y1 = data[1]; 465 x2 = data[2]; 466 y2 = data[3]; 467 x3 = data[4]; 468 y3 = data[5]; 469 map_if_relative(ox, oy, relative, &x1, &y1); 470 map_if_relative(ox, oy, relative, &x2, &y2); 471 map_if_relative(ox, oy, relative, &x3, &y3); 472 ox = x3; 473 oy = y3; 474 px = x2; 475 py = y2; 476 assert(matrix_is_affine(matrix)); 477 matrix_map_point(matrix, x0, y0, &x0, &y0); 478 matrix_map_point(matrix, x1, y1, &x1, &y1); 479 matrix_map_point(matrix, x2, y2, &x2, &y2); 480 matrix_map_point(matrix, x3, y3, &x3, &y3); 481 bezier_init(&bezier, x0, y0, x1, y1, 482 x2, y2, x3, y3); 483 bezier_add_to_polygon(&bezier, current); 484 } 485 break; 486 case VG_QUAD_TO: { 487 struct bezier bezier; 488 data_at(&coords, p, 0, 4, data); 489 x0 = ox; 490 y0 = oy; 491 x1 = data[0]; 492 y1 = data[1]; 493 x3 = data[2]; 494 y3 = data[3]; 495 map_if_relative(ox, oy, relative, &x1, &y1); 496 map_if_relative(ox, oy, relative, &x3, &y3); 497 px = x1; 498 py = y1; 499 { /* form a cubic out of it */ 500 x2 = (x3 + 2*x1) / 3.f; 501 y2 = (y3 + 2*y1) / 3.f; 502 x1 = (x0 + 2*x1) / 3.f; 503 y1 = (y0 + 2*y1) / 3.f; 504 } 505 ox = x3; 506 oy = y3; 507 assert(matrix_is_affine(matrix)); 508 matrix_map_point(matrix, x0, y0, &x0, &y0); 509 matrix_map_point(matrix, x1, y1, &x1, &y1); 510 matrix_map_point(matrix, x2, y2, &x2, &y2); 511 matrix_map_point(matrix, x3, y3, &x3, &y3); 512 bezier_init(&bezier, x0, y0, x1, y1, 513 x2, y2, x3, y3); 514 bezier_add_to_polygon(&bezier, current); 515 } 516 break; 517 case VG_SQUAD_TO: { 518 struct bezier bezier; 519 data_at(&coords, p, 0, 2, data); 520 x0 = ox; 521 y0 = oy; 522 x1 = 2*ox-px; 523 y1 = 2*oy-py; 524 x3 = data[0]; 525 y3 = data[1]; 526 map_if_relative(ox, oy, relative, &x3, &y3); 527 px = x1; 528 py = y1; 529 { /* form a cubic out of it */ 530 x2 = (x3 + 2*x1) / 3.f; 531 y2 = (y3 + 2*y1) / 3.f; 532 x1 = (x0 + 2*x1) / 3.f; 533 y1 = (y0 + 2*y1) / 3.f; 534 } 535 ox = x3; 536 oy = y3; 537 assert(matrix_is_affine(matrix)); 538 matrix_map_point(matrix, x0, y0, &x0, &y0); 539 matrix_map_point(matrix, x1, y1, &x1, &y1); 540 matrix_map_point(matrix, x2, y2, &x2, &y2); 541 matrix_map_point(matrix, x3, y3, &x3, &y3); 542 bezier_init(&bezier, x0, y0, x1, y1, 543 x2, y2, x3, y3); 544 bezier_add_to_polygon(&bezier, current); 545 } 546 break; 547 case VG_SCUBIC_TO: { 548 struct bezier bezier; 549 data_at(&coords, p, 0, 4, data); 550 x0 = ox; 551 y0 = oy; 552 x1 = 2*ox-px; 553 y1 = 2*oy-py; 554 x2 = data[0]; 555 y2 = data[1]; 556 x3 = data[2]; 557 y3 = data[3]; 558 map_if_relative(ox, oy, relative, &x2, &y2); 559 map_if_relative(ox, oy, relative, &x3, &y3); 560 ox = x3; 561 oy = y3; 562 px = x2; 563 py = y2; 564 assert(matrix_is_affine(matrix)); 565 matrix_map_point(matrix, x0, y0, &x0, &y0); 566 matrix_map_point(matrix, x1, y1, &x1, &y1); 567 matrix_map_point(matrix, x2, y2, &x2, &y2); 568 matrix_map_point(matrix, x3, y3, &x3, &y3); 569 bezier_init(&bezier, x0, y0, x1, y1, 570 x2, y2, x3, y3); 571 bezier_add_to_polygon(&bezier, current); 572 } 573 break; 574 case VG_SCCWARC_TO: 575 case VG_SCWARC_TO: 576 case VG_LCCWARC_TO: 577 case VG_LCWARC_TO: { 578 VGfloat rh, rv, rot; 579 struct arc arc; 580 581 data_at(&coords, p, 0, 5, data); 582 x0 = ox; 583 y0 = oy; 584 rh = data[0]; 585 rv = data[1]; 586 rot = data[2]; 587 x1 = data[3]; 588 y1 = data[4]; 589 map_if_relative(ox, oy, relative, &x1, &y1); 590#if 0 591 debug_printf("------- ARC (%f, %f), (%f, %f) %f, %f, %f\n", 592 x0, y0, x1, y1, rh, rv, rot); 593#endif 594 arc_init(&arc, command, x0, y0, x1, y1, 595 rh, rv, rot); 596 arc_add_to_polygon(&arc, current, 597 matrix); 598 ox = x1; 599 oy = y1; 600 px = x1; 601 py = y1; 602 } 603 break; 604 default: 605 abort(); 606 assert(!"Unknown segment!"); 607 } 608 } 609 if (current) { 610 if (polygon_vertex_count(current) > 0) { 611 close_polygon(current, sx, sy, ox, oy, matrix); 612 array_append_data(array, ¤t, 1); 613 } else 614 polygon_destroy(current); 615 } 616 617 p->fill_polys.polygon_array.array = array; 618 p->fill_polys.matrix = *matrix; 619 620 polygon_array_calculate_bounds( &p->fill_polys.polygon_array ); 621 622 p->dirty = VG_FALSE; 623 624 return &p->fill_polys.polygon_array; 625} 626 627VGbyte path_datatype_size(struct path *p) 628{ 629 return size_for_datatype(p->datatype); 630} 631 632VGPathDatatype path_datatype(struct path *p) 633{ 634 return p->datatype; 635} 636 637VGfloat path_scale(struct path *p) 638{ 639 return p->scale; 640} 641 642VGfloat path_bias(struct path *p) 643{ 644 return p->bias; 645} 646 647VGint path_num_coords(struct path *p) 648{ 649 return num_elements_for_segments((VGubyte*)p->segments->data, 650 p->num_segments); 651} 652 653void path_modify_coords(struct path *p, 654 VGint startIndex, 655 VGint numSegments, 656 const void * pathData) 657{ 658 VGubyte *segments = (VGubyte*)(p->segments->data); 659 VGint count = num_elements_for_segments(&segments[startIndex], numSegments); 660 VGint start_cp = num_elements_for_segments(segments, startIndex); 661 662 array_change_data(p->control_points, pathData, start_cp, count); 663 coords_adjust_by_scale_bias(p, 664 ((VGubyte*)p->control_points->data) + 665 (startIndex * p->control_points->datatype_size), 666 path_num_coords(p), 667 p->scale, p->bias, p->datatype); 668 p->dirty = VG_TRUE; 669 p->dirty_stroke = VG_TRUE; 670} 671 672void path_for_each_segment(struct path *path, 673 path_for_each_cb cb, 674 void *user_data) 675{ 676 VGint i; 677 struct path_for_each_data p; 678 VGfloat data[8]; 679 void *coords = (VGfloat *)path->control_points->data; 680 681 p.coords = data; 682 p.sx = p.sy = p.px = p.py = p.ox = p.oy = 0.f; 683 p.user_data = user_data; 684 685 for (i = 0; i < path->num_segments; ++i) { 686 VGint command; 687 VGboolean relative; 688 689 p.segment = ((VGubyte*)(path->segments->data))[i]; 690 command = SEGMENT_COMMAND(p.segment); 691 relative = SEGMENT_ABS_REL(p.segment); 692 693 switch(command) { 694 case VG_CLOSE_PATH: 695 cb(path, &p); 696 break; 697 case VG_MOVE_TO: 698 data_at(&coords, path, 0, 2, data); 699 map_if_relative(p.ox, p.oy, relative, &data[0], &data[1]); 700 cb(path, &p); 701 p.sx = data[0]; 702 p.sy = data[1]; 703 p.ox = data[0]; 704 p.oy = data[1]; 705 p.px = data[0]; 706 p.py = data[1]; 707 break; 708 case VG_LINE_TO: 709 data_at(&coords, path, 0, 2, data); 710 map_if_relative(p.ox, p.oy, relative, &data[0], &data[1]); 711 cb(path, &p); 712 p.ox = data[0]; 713 p.oy = data[1]; 714 p.px = data[0]; 715 p.py = data[1]; 716 break; 717 case VG_HLINE_TO: 718 data_at(&coords, path, 0, 1, data); 719 map_if_relative(p.ox, p.oy, relative, &data[0], 0); 720 p.segment = VG_LINE_TO; 721 data[1] = p.oy; 722 cb(path, &p); 723 p.ox = data[0]; 724 p.oy = data[1]; 725 p.px = data[0]; 726 p.py = data[1]; 727 break; 728 case VG_VLINE_TO: 729 data_at(&coords, path, 0, 1, data); 730 map_if_relative(p.ox, p.oy, relative, 0, &data[0]); 731 p.segment = VG_LINE_TO; 732 data[1] = data[0]; 733 data[0] = p.ox; 734 cb(path, &p); 735 p.ox = data[0]; 736 p.oy = data[1]; 737 p.px = data[0]; 738 p.py = data[1]; 739 break; 740 case VG_CUBIC_TO: { 741 data_at(&coords, path, 0, 6, data); 742 map_if_relative(p.ox, p.oy, relative, &data[0], &data[1]); 743 map_if_relative(p.ox, p.oy, relative, &data[2], &data[3]); 744 map_if_relative(p.ox, p.oy, relative, &data[4], &data[5]); 745 cb(path, &p); 746 p.px = data[2]; 747 p.py = data[3]; 748 p.ox = data[4]; 749 p.oy = data[5]; 750 } 751 break; 752 case VG_QUAD_TO: { 753 data_at(&coords, path, 0, 4, data); 754 map_if_relative(p.ox, p.oy, relative, &data[0], &data[1]); 755 map_if_relative(p.ox, p.oy, relative, &data[2], &data[3]); 756 cb(path, &p); 757 p.px = data[0]; 758 p.py = data[1]; 759 p.ox = data[2]; 760 p.oy = data[3]; 761 } 762 break; 763 case VG_SQUAD_TO: { 764 data_at(&coords, path, 0, 2, data); 765 map_if_relative(p.ox, p.oy, relative, &data[0], &data[1]); 766 cb(path, &p); 767 p.px = 2*p.ox-p.px; 768 p.py = 2*p.oy-p.py; 769 p.ox = data[2]; 770 p.oy = data[3]; 771 } 772 break; 773 case VG_SCUBIC_TO: { 774 data_at(&coords, path, 0, 4, data); 775 map_if_relative(p.ox, p.oy, relative, &data[0], &data[1]); 776 map_if_relative(p.ox, p.oy, relative, &data[2], &data[3]); 777 cb(path, &p); 778 p.px = data[0]; 779 p.py = data[1]; 780 p.ox = data[2]; 781 p.oy = data[3]; 782 } 783 break; 784 case VG_SCCWARC_TO: 785 case VG_SCWARC_TO: 786 case VG_LCCWARC_TO: 787 case VG_LCWARC_TO: { 788 data_at(&coords, path, 0, 5, data); 789 map_if_relative(p.ox, p.oy, relative, &data[3], &data[4]); 790#if 0 791 debug_printf("------- ARC (%f, %f), (%f, %f) %f, %f, %f\n", 792 p.ox, p.oy, data[3], data[4], data[0], data[1], data[2]); 793#endif 794 cb(path, &p); 795 p.ox = data[3]; 796 p.oy = data[4]; 797 p.px = data[3]; 798 p.py = data[4]; 799 } 800 break; 801 default: 802 abort(); 803 assert(!"Unknown segment!"); 804 } 805 } 806} 807 808struct transform_data { 809 struct array *segments; 810 struct array *coords; 811 812 struct matrix *matrix; 813 814 VGPathDatatype datatype; 815}; 816 817static VGboolean transform_cb(struct path *p, 818 struct path_for_each_data *pd) 819{ 820 struct transform_data *td = (struct transform_data *)pd->user_data; 821 VGint num_coords = num_elements_for_segments(&pd->segment, 1); 822 VGubyte segment = SEGMENT_COMMAND(pd->segment);/* abs bit is 0 */ 823 VGfloat data[8]; 824 VGubyte common_data[sizeof(VGfloat)*8]; 825 826 memcpy(data, pd->coords, sizeof(VGfloat) * num_coords); 827 828 switch(segment) { 829 case VG_CLOSE_PATH: 830 break; 831 case VG_MOVE_TO: 832 matrix_map_point(td->matrix, 833 data[0], data[1], &data[0], &data[1]); 834 break; 835 case VG_LINE_TO: 836 matrix_map_point(td->matrix, 837 data[0], data[1], &data[0], &data[1]); 838 break; 839 case VG_HLINE_TO: 840 case VG_VLINE_TO: 841 assert(0); 842 break; 843 case VG_QUAD_TO: 844 matrix_map_point(td->matrix, 845 data[0], data[1], &data[0], &data[1]); 846 matrix_map_point(td->matrix, 847 data[2], data[3], &data[2], &data[3]); 848 break; 849 case VG_CUBIC_TO: 850 matrix_map_point(td->matrix, 851 data[0], data[1], &data[0], &data[1]); 852 matrix_map_point(td->matrix, 853 data[2], data[3], &data[2], &data[3]); 854 matrix_map_point(td->matrix, 855 data[4], data[5], &data[4], &data[5]); 856 break; 857 case VG_SQUAD_TO: 858 matrix_map_point(td->matrix, 859 data[0], data[1], &data[0], &data[1]); 860 break; 861 case VG_SCUBIC_TO: 862 matrix_map_point(td->matrix, 863 data[0], data[1], &data[0], &data[1]); 864 matrix_map_point(td->matrix, 865 data[2], data[3], &data[2], &data[3]); 866 break; 867 case VG_SCCWARC_TO: 868 case VG_SCWARC_TO: 869 case VG_LCCWARC_TO: 870 case VG_LCWARC_TO: { 871 struct arc arc; 872 struct path *path = path_create(td->datatype, 873 1, 0, 0, 0, VG_PATH_CAPABILITY_ALL); 874 arc_init(&arc, segment, 875 pd->ox, pd->oy, data[3], data[4], 876 data[0], data[1], data[2]); 877 878 arc_to_path(&arc, path, td->matrix); 879 880 num_coords = path_num_coords(path); 881 882 array_append_data(td->segments, path->segments->data, 883 path->num_segments); 884 array_append_data(td->coords, path->control_points->data, 885 num_coords); 886 path_destroy(path); 887 888 return VG_TRUE; 889 } 890 break; 891 default: 892 break; 893 } 894 895 vg_float_to_datatype(td->datatype, common_data, data, num_coords); 896 897 array_append_data(td->segments, &pd->segment, 1); 898 array_append_data(td->coords, common_data, num_coords); 899 return VG_TRUE; 900} 901 902void path_transform(struct path *dst, struct path *src) 903{ 904 struct transform_data data; 905 struct vg_context *ctx = dst->base.ctx; 906 907 data.segments = dst->segments; 908 data.coords = dst->control_points; 909 data.matrix = &ctx->state.vg.path_user_to_surface_matrix; 910 data.datatype = dst->datatype; 911 912 path_for_each_segment(src, transform_cb, (void*)&data); 913 914 dst->num_segments = dst->segments->num_elements; 915 dst->dirty = VG_TRUE; 916 dst->dirty_stroke = VG_TRUE; 917} 918 919void path_append_path(struct path *dst, 920 struct path *src) 921{ 922 VGint num_coords = path_num_coords(src); 923 void *dst_data = malloc(size_for_datatype(dst->datatype) * num_coords); 924 array_append_data(dst->segments, 925 src->segments->data, 926 src->num_segments); 927 convert_path(src, dst->datatype, 928 dst_data, num_coords); 929 array_append_data(dst->control_points, 930 dst_data, 931 num_coords); 932 free(dst_data); 933 934 dst->num_segments += src->num_segments; 935 dst->dirty = VG_TRUE; 936 dst->dirty_stroke = VG_TRUE; 937} 938 939static INLINE VGboolean is_segment_arc(VGubyte segment) 940{ 941 VGubyte scommand = SEGMENT_COMMAND(segment); 942 return (scommand == VG_SCCWARC_TO || 943 scommand == VG_SCWARC_TO || 944 scommand == VG_LCCWARC_TO || 945 scommand == VG_LCWARC_TO); 946} 947 948struct path_iter_data { 949 struct path *path; 950 VGubyte segment; 951 void *coords; 952 VGfloat px, py, ox, oy, sx, sy; 953}; 954static INLINE VGubyte normalize_coords(struct path_iter_data *pd, 955 VGint *num_coords, 956 VGfloat *data) 957{ 958 VGint command = SEGMENT_COMMAND(pd->segment); 959 VGboolean relative = SEGMENT_ABS_REL(pd->segment); 960 961 switch(command) { 962 case VG_CLOSE_PATH: 963 *num_coords = 0; 964 pd->ox = pd->sx; 965 pd->oy = pd->sy; 966 return VG_CLOSE_PATH; 967 break; 968 case VG_MOVE_TO: 969 data_at(&pd->coords, pd->path, 0, 2, data); 970 map_if_relative(pd->ox, pd->oy, relative, &data[0], &data[1]); 971 pd->sx = data[0]; 972 pd->sy = data[1]; 973 pd->ox = data[0]; 974 pd->oy = data[1]; 975 pd->px = data[0]; 976 pd->py = data[1]; 977 *num_coords = 2; 978 return VG_MOVE_TO_ABS; 979 break; 980 case VG_LINE_TO: 981 data_at(&pd->coords, pd->path, 0, 2, data); 982 map_if_relative(pd->ox, pd->oy, relative, &data[0], &data[1]); 983 pd->ox = data[0]; 984 pd->oy = data[1]; 985 pd->px = data[0]; 986 pd->py = data[1]; 987 *num_coords = 2; 988 return VG_LINE_TO_ABS; 989 break; 990 case VG_HLINE_TO: 991 data_at(&pd->coords, pd->path, 0, 1, data); 992 map_if_relative(pd->ox, pd->oy, relative, &data[0], 0); 993 data[1] = pd->oy; 994 pd->ox = data[0]; 995 pd->oy = data[1]; 996 pd->px = data[0]; 997 pd->py = data[1]; 998 *num_coords = 2; 999 return VG_LINE_TO_ABS; 1000 break; 1001 case VG_VLINE_TO: 1002 data_at(&pd->coords, pd->path, 0, 1, data); 1003 map_if_relative(pd->ox, pd->oy, relative, 0, &data[0]); 1004 data[1] = data[0]; 1005 data[0] = pd->ox; 1006 pd->ox = data[0]; 1007 pd->oy = data[1]; 1008 pd->px = data[0]; 1009 pd->py = data[1]; 1010 *num_coords = 2; 1011 return VG_LINE_TO_ABS; 1012 break; 1013 case VG_CUBIC_TO: { 1014 data_at(&pd->coords, pd->path, 0, 6, data); 1015 map_if_relative(pd->ox, pd->oy, relative, &data[0], &data[1]); 1016 map_if_relative(pd->ox, pd->oy, relative, &data[2], &data[3]); 1017 map_if_relative(pd->ox, pd->oy, relative, &data[4], &data[5]); 1018 pd->px = data[2]; 1019 pd->py = data[3]; 1020 pd->ox = data[4]; 1021 pd->oy = data[5]; 1022 *num_coords = 6; 1023 return VG_CUBIC_TO_ABS; 1024 } 1025 break; 1026 case VG_QUAD_TO: { 1027 VGfloat x0, y0, x1, y1, x2, y2, x3, y3; 1028 data_at(&pd->coords, pd->path, 0, 4, data); 1029 x0 = pd->ox; 1030 y0 = pd->oy; 1031 x1 = data[0]; 1032 y1 = data[1]; 1033 x3 = data[2]; 1034 y3 = data[3]; 1035 map_if_relative(pd->ox, pd->oy, relative, &x1, &y1); 1036 map_if_relative(pd->ox, pd->oy, relative, &x3, &y3); 1037 pd->px = x1; 1038 pd->py = y1; 1039 { /* form a cubic out of it */ 1040 x2 = (x3 + 2*x1) / 3.f; 1041 y2 = (y3 + 2*y1) / 3.f; 1042 x1 = (x0 + 2*x1) / 3.f; 1043 y1 = (y0 + 2*y1) / 3.f; 1044 } 1045 pd->ox = x3; 1046 pd->oy = y3; 1047 data[0] = x1; 1048 data[1] = y1; 1049 data[2] = x2; 1050 data[3] = y2; 1051 data[4] = x3; 1052 data[5] = y3; 1053 *num_coords = 6; 1054 return VG_CUBIC_TO_ABS; 1055 } 1056 break; 1057 case VG_SQUAD_TO: { 1058 VGfloat x0, y0, x1, y1, x2, y2, x3, y3; 1059 data_at(&pd->coords, pd->path, 0, 2, data); 1060 x0 = pd->ox; 1061 y0 = pd->oy; 1062 x1 = 2 * pd->ox - pd->px; 1063 y1 = 2 * pd->oy - pd->py; 1064 x3 = data[0]; 1065 y3 = data[1]; 1066 map_if_relative(pd->ox, pd->oy, relative, &x3, &y3); 1067 pd->px = x1; 1068 pd->py = y1; 1069 { /* form a cubic out of it */ 1070 x2 = (x3 + 2*x1) / 3.f; 1071 y2 = (y3 + 2*y1) / 3.f; 1072 x1 = (x0 + 2*x1) / 3.f; 1073 y1 = (y0 + 2*y1) / 3.f; 1074 } 1075 pd->ox = x3; 1076 pd->oy = y3; 1077 data[0] = x1; 1078 data[1] = y1; 1079 data[2] = x2; 1080 data[3] = y2; 1081 data[4] = x3; 1082 data[5] = y3; 1083 *num_coords = 6; 1084 return VG_CUBIC_TO_ABS; 1085 } 1086 break; 1087 case VG_SCUBIC_TO: { 1088 VGfloat x0, y0, x1, y1, x2, y2, x3, y3; 1089 data_at(&pd->coords, pd->path, 0, 4, data); 1090 x0 = pd->ox; 1091 y0 = pd->oy; 1092 x1 = 2*pd->ox-pd->px; 1093 y1 = 2*pd->oy-pd->py; 1094 x2 = data[0]; 1095 y2 = data[1]; 1096 x3 = data[2]; 1097 y3 = data[3]; 1098 map_if_relative(pd->ox, pd->oy, relative, &x2, &y2); 1099 map_if_relative(pd->ox, pd->oy, relative, &x3, &y3); 1100 pd->ox = x3; 1101 pd->oy = y3; 1102 pd->px = x2; 1103 pd->py = y2; 1104 data[0] = x1; 1105 data[1] = y1; 1106 data[2] = x2; 1107 data[3] = y2; 1108 data[4] = x3; 1109 data[5] = y3; 1110 *num_coords = 6; 1111 return VG_CUBIC_TO_ABS; 1112 } 1113 break; 1114 case VG_SCCWARC_TO: 1115 case VG_SCWARC_TO: 1116 case VG_LCCWARC_TO: 1117 case VG_LCWARC_TO: { 1118 data_at(&pd->coords, pd->path, 0, 5, data); 1119 map_if_relative(pd->ox, pd->oy, relative, &data[3], &data[4]); 1120 pd->ox = data[3]; 1121 pd->oy = data[4]; 1122 pd->px = data[3]; 1123 pd->py = data[4]; 1124 *num_coords = 5; 1125 return command | VG_ABSOLUTE; 1126 } 1127 break; 1128 default: 1129 abort(); 1130 assert(!"Unknown segment!"); 1131 } 1132} 1133 1134static void linearly_interpolate(VGfloat *result, 1135 const VGfloat *start, 1136 const VGfloat *end, 1137 VGfloat amount, 1138 VGint number) 1139{ 1140 VGint i; 1141 for (i = 0; i < number; ++i) { 1142 result[i] = start[i] + (end[i] - start[i]) * amount; 1143 } 1144} 1145 1146VGboolean path_interpolate(struct path *dst, 1147 struct path *start, struct path *end, 1148 VGfloat amount) 1149{ 1150 /* temporary path that we can discard if it will turn 1151 * out that start is not compatible with end */ 1152 struct path *res_path = path_create(dst->datatype, 1153 1.0, 0.0, 1154 0, 0, dst->caps); 1155 VGint i; 1156 VGfloat start_coords[8]; 1157 VGfloat end_coords[8]; 1158 VGfloat results[8]; 1159 VGubyte common_data[sizeof(VGfloat)*8]; 1160 struct path_iter_data start_iter, end_iter; 1161 1162 memset(&start_iter, 0, sizeof(struct path_iter_data)); 1163 memset(&end_iter, 0, sizeof(struct path_iter_data)); 1164 1165 start_iter.path = start; 1166 start_iter.coords = start->control_points->data; 1167 end_iter.path = end; 1168 end_iter.coords = end->control_points->data; 1169 1170 for (i = 0; i < start->num_segments; ++i) { 1171 VGubyte segment; 1172 VGubyte ssegment, esegment; 1173 VGint snum_coords, enum_coords; 1174 start_iter.segment = ((VGubyte*)(start->segments->data))[i]; 1175 end_iter.segment = ((VGubyte*)(end->segments->data))[i]; 1176 1177 ssegment = normalize_coords(&start_iter, &snum_coords, 1178 start_coords); 1179 esegment = normalize_coords(&end_iter, &enum_coords, 1180 end_coords); 1181 1182 if (is_segment_arc(ssegment)) { 1183 if (!is_segment_arc(esegment)) { 1184 path_destroy(res_path); 1185 return VG_FALSE; 1186 } 1187 if (amount > 0.5) 1188 segment = esegment; 1189 else 1190 segment = ssegment; 1191 } else if (is_segment_arc(esegment)) { 1192 path_destroy(res_path); 1193 return VG_FALSE; 1194 } 1195 else if (ssegment != esegment) { 1196 path_destroy(res_path); 1197 return VG_FALSE; 1198 } 1199 else 1200 segment = ssegment; 1201 1202 linearly_interpolate(results, start_coords, end_coords, 1203 amount, snum_coords); 1204 vg_float_to_datatype(dst->datatype, common_data, results, snum_coords); 1205 path_append_data(res_path, 1, &segment, common_data); 1206 } 1207 1208 path_append_path(dst, res_path); 1209 path_destroy(res_path); 1210 1211 dst->dirty = VG_TRUE; 1212 dst->dirty_stroke = VG_TRUE; 1213 1214 return VG_TRUE; 1215} 1216 1217void path_clear(struct path *p, VGbitfield capabilities) 1218{ 1219 path_set_capabilities(p, capabilities); 1220 array_destroy(p->segments); 1221 array_destroy(p->control_points); 1222 p->segments = array_create(size_for_datatype(VG_PATH_DATATYPE_S_8)); 1223 p->control_points = array_create(size_for_datatype(p->datatype)); 1224 p->num_segments = 0; 1225 p->dirty = VG_TRUE; 1226 p->dirty_stroke = VG_TRUE; 1227} 1228 1229struct path * path_create_stroke(struct path *p, 1230 struct matrix *matrix) 1231{ 1232 VGint i; 1233 VGfloat sx, sy, px, py, ox, oy; 1234 VGfloat x0, y0, x1, y1, x2, y2, x3, y3; 1235 VGfloat data[8]; 1236 void *coords = (VGfloat *)p->control_points->data; 1237 int dashed = (p->base.ctx->state.vg.stroke.dash_pattern_num ? 1 : 0); 1238 struct dash_stroker stroker; 1239 struct vg_state *vg_state = &p->base.ctx->state.vg; 1240 1241 if (p->stroked.path) 1242 { 1243 /* ### compare the dash patterns to see if we can cache them. 1244 * for now we simply always bail out if the path is dashed. 1245 */ 1246 if (memcmp( &p->stroked.matrix, 1247 matrix, 1248 sizeof *matrix ) == 0 && 1249 !dashed && !p->dirty_stroke && 1250 floatsEqual(p->stroked.stroke_width, vg_state->stroke.line_width.f) && 1251 floatsEqual(p->stroked.miter_limit, vg_state->stroke.miter_limit.f) && 1252 p->stroked.cap_style == vg_state->stroke.cap_style && 1253 p->stroked.join_style == vg_state->stroke.join_style) 1254 { 1255 return p->stroked.path; 1256 } 1257 else { 1258 path_destroy( p->stroked.path ); 1259 p->stroked.path = NULL; 1260 } 1261 } 1262 1263 1264 sx = sy = px = py = ox = oy = 0.f; 1265 1266 if (dashed) 1267 dash_stroker_init((struct stroker *)&stroker, vg_state); 1268 else 1269 stroker_init((struct stroker *)&stroker, vg_state); 1270 1271 stroker_begin((struct stroker *)&stroker); 1272 1273 for (i = 0; i < p->num_segments; ++i) { 1274 VGubyte segment = ((VGubyte*)(p->segments->data))[i]; 1275 VGint command = SEGMENT_COMMAND(segment); 1276 VGboolean relative = SEGMENT_ABS_REL(segment); 1277 1278 switch(command) { 1279 case VG_CLOSE_PATH: { 1280 VGfloat x0 = sx; 1281 VGfloat y0 = sy; 1282 matrix_map_point(matrix, x0, y0, &x0, &y0); 1283 stroker_line_to((struct stroker *)&stroker, x0, y0); 1284 } 1285 break; 1286 case VG_MOVE_TO: 1287 data_at(&coords, p, 0, 2, data); 1288 x0 = data[0]; 1289 y0 = data[1]; 1290 map_if_relative(ox, oy, relative, &x0, &y0); 1291 sx = x0; 1292 sy = y0; 1293 ox = x0; 1294 oy = y0; 1295 px = x0; 1296 py = y0; 1297 matrix_map_point(matrix, x0, y0, &x0, &y0); 1298 stroker_move_to((struct stroker *)&stroker, x0, y0); 1299 break; 1300 case VG_LINE_TO: 1301 data_at(&coords, p, 0, 2, data); 1302 x0 = data[0]; 1303 y0 = data[1]; 1304 map_if_relative(ox, oy, relative, &x0, &y0); 1305 ox = x0; 1306 oy = y0; 1307 px = x0; 1308 py = y0; 1309 matrix_map_point(matrix, x0, y0, &x0, &y0); 1310 stroker_line_to((struct stroker *)&stroker, x0, y0); 1311 break; 1312 case VG_HLINE_TO: 1313 data_at(&coords, p, 0, 1, data); 1314 x0 = data[0]; 1315 y0 = oy; 1316 map_if_relative(ox, oy, relative, &x0, 0); 1317 ox = x0; 1318 px = x0; 1319 py = y0; 1320 matrix_map_point(matrix, x0, y0, &x0, &y0); 1321 stroker_line_to((struct stroker *)&stroker, x0, y0); 1322 break; 1323 case VG_VLINE_TO: 1324 data_at(&coords, p, 0, 1, data); 1325 x0 = ox; 1326 y0 = data[0]; 1327 map_if_relative(ox, oy, relative, 0, &y0); 1328 oy = y0; 1329 px = x0; 1330 py = y0; 1331 matrix_map_point(matrix, x0, y0, &x0, &y0); 1332 stroker_line_to((struct stroker *)&stroker, x0, y0); 1333 break; 1334 case VG_CUBIC_TO: { 1335 data_at(&coords, p, 0, 6, data); 1336 x0 = ox; 1337 y0 = oy; 1338 x1 = data[0]; 1339 y1 = data[1]; 1340 x2 = data[2]; 1341 y2 = data[3]; 1342 x3 = data[4]; 1343 y3 = data[5]; 1344 map_if_relative(ox, oy, relative, &x1, &y1); 1345 map_if_relative(ox, oy, relative, &x2, &y2); 1346 map_if_relative(ox, oy, relative, &x3, &y3); 1347 if (floatsEqual(x1, ox) && floatsEqual(y1, oy) && 1348 floatsEqual(x1, x2) && floatsEqual(y1, y2) && 1349 floatsEqual(x2, x3) && floatsEqual(y2, y3)) { 1350 /*ignore the empty segment */ 1351 continue; 1352 } else if (floatsEqual(x3, ox) && floatsEqual(y3, oy)) { 1353 /* if dup vertex, emit a line */ 1354 ox = x3; 1355 oy = y3; 1356 matrix_map_point(matrix, x3, y3, &x3, &y3); 1357 stroker_line_to((struct stroker *)&stroker, x3, y3); 1358 continue; 1359 } 1360 ox = x3; 1361 oy = y3; 1362 px = x2; 1363 py = y2; 1364 assert(matrix_is_affine(matrix)); 1365 matrix_map_point(matrix, x0, y0, &x0, &y0); 1366 matrix_map_point(matrix, x1, y1, &x1, &y1); 1367 matrix_map_point(matrix, x2, y2, &x2, &y2); 1368 matrix_map_point(matrix, x3, y3, &x3, &y3); 1369 stroker_curve_to((struct stroker *)&stroker, x1, y1, x2, y2, x3, y3); 1370 } 1371 break; 1372 case VG_QUAD_TO: { 1373 data_at(&coords, p, 0, 4, data); 1374 x0 = ox; 1375 y0 = oy; 1376 x1 = data[0]; 1377 y1 = data[1]; 1378 x3 = data[2]; 1379 y3 = data[3]; 1380 map_if_relative(ox, oy, relative, &x1, &y1); 1381 map_if_relative(ox, oy, relative, &x3, &y3); 1382 px = x1; 1383 py = y1; 1384 { /* form a cubic out of it */ 1385 x2 = (x3 + 2*x1) / 3.f; 1386 y2 = (y3 + 2*y1) / 3.f; 1387 x1 = (x0 + 2*x1) / 3.f; 1388 y1 = (y0 + 2*y1) / 3.f; 1389 } 1390 if (floatsEqual(x1, ox) && floatsEqual(y1, oy) && 1391 floatsEqual(x1, x2) && floatsEqual(y1, y2) && 1392 floatsEqual(x2, x3) && floatsEqual(y2, y3)) { 1393 /*ignore the empty segment */ 1394 continue; 1395 } else if (floatsEqual(x3, ox) && floatsEqual(y3, oy)) { 1396 /* if dup vertex, emit a line */ 1397 ox = x3; 1398 oy = y3; 1399 matrix_map_point(matrix, x3, y3, &x3, &y3); 1400 stroker_line_to((struct stroker *)&stroker, x3, y3); 1401 continue; 1402 } 1403 ox = x3; 1404 oy = y3; 1405 assert(matrix_is_affine(matrix)); 1406 matrix_map_point(matrix, x0, y0, &x0, &y0); 1407 matrix_map_point(matrix, x1, y1, &x1, &y1); 1408 matrix_map_point(matrix, x2, y2, &x2, &y2); 1409 matrix_map_point(matrix, x3, y3, &x3, &y3); 1410 stroker_curve_to((struct stroker *)&stroker, x1, y1, x2, y2, x3, y3); 1411 } 1412 break; 1413 case VG_SQUAD_TO: { 1414 data_at(&coords, p, 0, 2, data); 1415 x0 = ox; 1416 y0 = oy; 1417 x1 = 2*ox-px; 1418 y1 = 2*oy-py; 1419 x3 = data[0]; 1420 y3 = data[1]; 1421 map_if_relative(ox, oy, relative, &x3, &y3); 1422 px = x1; 1423 py = y1; 1424 { /* form a cubic out of it */ 1425 x2 = (x3 + 2*x1) / 3.f; 1426 y2 = (y3 + 2*y1) / 3.f; 1427 x1 = (x0 + 2*x1) / 3.f; 1428 y1 = (y0 + 2*y1) / 3.f; 1429 } 1430 if (floatsEqual(x1, ox) && floatsEqual(y1, oy) && 1431 floatsEqual(x1, x2) && floatsEqual(y1, y2) && 1432 floatsEqual(x2, x3) && floatsEqual(y2, y3)) { 1433 /*ignore the empty segment */ 1434 continue; 1435 } else if (floatsEqual(x3, ox) && floatsEqual(y3, oy)) { 1436 /* if dup vertex, emit a line */ 1437 ox = x3; 1438 oy = y3; 1439 matrix_map_point(matrix, x3, y3, &x3, &y3); 1440 stroker_line_to((struct stroker *)&stroker, x3, y3); 1441 continue; 1442 } 1443 ox = x3; 1444 oy = y3; 1445 assert(matrix_is_affine(matrix)); 1446 matrix_map_point(matrix, x0, y0, &x0, &y0); 1447 matrix_map_point(matrix, x1, y1, &x1, &y1); 1448 matrix_map_point(matrix, x2, y2, &x2, &y2); 1449 matrix_map_point(matrix, x3, y3, &x3, &y3); 1450 stroker_curve_to((struct stroker *)&stroker, x1, y1, x2, y2, x3, y3); 1451 } 1452 break; 1453 case VG_SCUBIC_TO: { 1454 data_at(&coords, p, 0, 4, data); 1455 x0 = ox; 1456 y0 = oy; 1457 x1 = 2*ox-px; 1458 y1 = 2*oy-py; 1459 x2 = data[0]; 1460 y2 = data[1]; 1461 x3 = data[2]; 1462 y3 = data[3]; 1463 map_if_relative(ox, oy, relative, &x2, &y2); 1464 map_if_relative(ox, oy, relative, &x3, &y3); 1465 if (floatsEqual(x1, ox) && floatsEqual(y1, oy) && 1466 floatsEqual(x1, x2) && floatsEqual(y1, y2) && 1467 floatsEqual(x2, x3) && floatsEqual(y2, y3)) { 1468 /*ignore the empty segment */ 1469 continue; 1470 } else if (floatsEqual(x3, ox) && floatsEqual(y3, oy)) { 1471 /* if dup vertex, emit a line */ 1472 ox = x3; 1473 oy = y3; 1474 matrix_map_point(matrix, x3, y3, &x3, &y3); 1475 stroker_line_to((struct stroker *)&stroker, x3, y3); 1476 continue; 1477 } 1478 ox = x3; 1479 oy = y3; 1480 px = x2; 1481 py = y2; 1482 assert(matrix_is_affine(matrix)); 1483 matrix_map_point(matrix, x0, y0, &x0, &y0); 1484 matrix_map_point(matrix, x1, y1, &x1, &y1); 1485 matrix_map_point(matrix, x2, y2, &x2, &y2); 1486 matrix_map_point(matrix, x3, y3, &x3, &y3); 1487 stroker_curve_to((struct stroker *)&stroker, x1, y1, x2, y2, x3, y3); 1488 } 1489 break; 1490 case VG_SCCWARC_TO: 1491 case VG_SCWARC_TO: 1492 case VG_LCCWARC_TO: 1493 case VG_LCWARC_TO: { 1494 VGfloat rh, rv, rot; 1495 struct arc arc; 1496 1497 data_at(&coords, p, 0, 5, data); 1498 x0 = ox; 1499 y0 = oy; 1500 rh = data[0]; 1501 rv = data[1]; 1502 rot = data[2]; 1503 x1 = data[3]; 1504 y1 = data[4]; 1505 map_if_relative(ox, oy, relative, &x1, &y1); 1506 if (floatsEqual(x1, ox) && floatsEqual(y1, oy)) { 1507 /* if dup vertex, emit a line */ 1508 ox = x1; 1509 oy = y1; 1510 matrix_map_point(matrix, x1, y1, &x1, &y1); 1511 stroker_line_to((struct stroker *)&stroker, x1, y1); 1512 continue; 1513 } 1514 arc_init(&arc, command, x0, y0, x1, y1, 1515 rh, rv, rot); 1516 arc_stroke_cb(&arc, (struct stroker *)&stroker, 1517 matrix); 1518 ox = x1; 1519 oy = y1; 1520 px = x1; 1521 py = y1; 1522 } 1523 break; 1524 default: 1525 abort(); 1526 assert(!"Unknown segment!"); 1527 } 1528 } 1529 1530 stroker_end((struct stroker *)&stroker); 1531 1532 if (dashed) 1533 dash_stroker_cleanup((struct dash_stroker *)&stroker); 1534 else 1535 stroker_cleanup((struct stroker *)&stroker); 1536 1537 p->stroked.path = stroker.base.path; 1538 p->stroked.matrix = *matrix; 1539 p->dirty_stroke = VG_FALSE; 1540 p->stroked.stroke_width = vg_state->stroke.line_width.f; 1541 p->stroked.miter_limit = vg_state->stroke.miter_limit.f; 1542 p->stroked.cap_style = vg_state->stroke.cap_style; 1543 p->stroked.join_style = vg_state->stroke.join_style; 1544 1545 return stroker.base.path; 1546} 1547 1548void path_render(struct path *p, VGbitfield paintModes, 1549 struct matrix *mat) 1550{ 1551 struct vg_context *ctx = vg_current_context(); 1552 struct matrix paint_matrix; 1553 1554 vg_validate_state(ctx); 1555 1556 shader_set_drawing_image(ctx->shader, VG_FALSE); 1557 shader_set_image(ctx->shader, 0); 1558#if 0 1559 fprintf(stderr, "Matrix(11=%f 12=%f 13=%f 21=%f 22=%f 23=%f 31=%f 32=%f 33=%f)\n", 1560 mat->m[0], mat->m[1], mat->m[2], 1561 mat->m[3], mat->m[4], mat->m[5], 1562 mat->m[6], mat->m[7], mat->m[8]); 1563#endif 1564 if ((paintModes & VG_FILL_PATH) && 1565 vg_get_paint_matrix(ctx, 1566 &ctx->state.vg.fill_paint_to_user_matrix, 1567 mat, 1568 &paint_matrix)) { 1569 /* First the fill */ 1570 shader_set_surface_matrix(ctx->shader, mat); 1571 shader_set_paint(ctx->shader, ctx->state.vg.fill_paint); 1572 shader_set_paint_matrix(ctx->shader, &paint_matrix); 1573 shader_bind(ctx->shader); 1574 path_fill(p); 1575 } 1576 1577 if ((paintModes & VG_STROKE_PATH) && 1578 vg_get_paint_matrix(ctx, 1579 &ctx->state.vg.stroke_paint_to_user_matrix, 1580 mat, 1581 &paint_matrix)) { 1582 /* 8.7.5: "line width less than or equal to 0 prevents stroking from 1583 * taking place."*/ 1584 if (ctx->state.vg.stroke.line_width.f <= 0) 1585 return; 1586 shader_set_surface_matrix(ctx->shader, mat); 1587 shader_set_paint(ctx->shader, ctx->state.vg.stroke_paint); 1588 shader_set_paint_matrix(ctx->shader, &paint_matrix); 1589 shader_bind(ctx->shader); 1590 path_stroke(p); 1591 } 1592} 1593 1594void path_fill(struct path *p) 1595{ 1596 struct vg_context *ctx = vg_current_context(); 1597 struct matrix identity; 1598 1599 matrix_load_identity(&identity); 1600 1601 { 1602 struct polygon_array *polygon_array = path_get_fill_polygons(p, &identity); 1603 struct array *polys = polygon_array->array; 1604 1605 if (!polygon_array || !polys || !polys->num_elements) { 1606 return; 1607 } 1608 polygon_array_fill(polygon_array, ctx); 1609 } 1610} 1611 1612void path_stroke(struct path *p) 1613{ 1614 struct vg_context *ctx = vg_current_context(); 1615 VGFillRule old_fill = ctx->state.vg.fill_rule; 1616 struct matrix identity; 1617 struct path *stroke; 1618 1619 matrix_load_identity(&identity); 1620 stroke = path_create_stroke(p, &identity); 1621 if (stroke && !path_is_empty(stroke)) { 1622 ctx->state.vg.fill_rule = VG_NON_ZERO; 1623 1624 path_fill(stroke); 1625 1626 ctx->state.vg.fill_rule = old_fill; 1627 } 1628} 1629 1630void path_move_to(struct path *p, float x, float y) 1631{ 1632 VGubyte segment = VG_MOVE_TO_ABS; 1633 VGubyte common_data[sizeof(VGfloat) * 2]; 1634 VGfloat data[2] = {x, y}; 1635 1636 vg_float_to_datatype(p->datatype, common_data, data, 2); 1637 path_append_data(p, 1, &segment, common_data); 1638} 1639 1640void path_line_to(struct path *p, float x, float y) 1641{ 1642 VGubyte segment = VG_LINE_TO_ABS; 1643 VGubyte common_data[sizeof(VGfloat) * 2]; 1644 VGfloat data[2] = {x, y}; 1645 1646 vg_float_to_datatype(p->datatype, common_data, data, 2); 1647 1648 path_append_data(p, 1, &segment, common_data); 1649} 1650 1651void path_cubic_to(struct path *p, float px1, float py1, 1652 float px2, float py2, 1653 float x, float y) 1654{ 1655 VGubyte segment = VG_CUBIC_TO_ABS; 1656 VGubyte common_data[sizeof(VGfloat) * 6]; 1657 VGfloat data[6]; 1658 1659 data[0] = px1; data[1] = py1; 1660 data[2] = px2; data[3] = py2; 1661 data[4] = x; data[5] = y; 1662 1663 vg_float_to_datatype(p->datatype, common_data, data, 6); 1664 1665 path_append_data(p, 1, &segment, common_data); 1666} 1667 1668static INLINE void line_bounds(VGfloat *line /*x1,y1,x2,y2*/, 1669 VGfloat *bounds) 1670{ 1671 bounds[0] = MIN2(line[0], line[2]); 1672 bounds[1] = MIN2(line[1], line[3]); 1673 bounds[2] = MAX2(line[0], line[2]) - bounds[0]; 1674 bounds[3] = MAX2(line[1], line[3]) - bounds[1]; 1675} 1676 1677static INLINE void unite_bounds(VGfloat *bounds, 1678 VGfloat *el) 1679{ 1680 VGfloat cx1, cy1, cx2, cy2; 1681 VGfloat nx1, ny1, nx2, ny2; 1682 1683 cx1 = bounds[0]; 1684 cy1 = bounds[1]; 1685 cx2 = bounds[0] + bounds[2]; 1686 cy2 = bounds[1] + bounds[3]; 1687 1688 nx1 = el[0]; 1689 ny1 = el[1]; 1690 nx2 = el[0] + el[2]; 1691 ny2 = el[1] + el[3]; 1692 1693 bounds[0] = MIN2(cx1, nx1); 1694 bounds[1] = MIN2(cy1, ny1); 1695 bounds[2] = MAX2(cx2, nx2) - bounds[0]; 1696 bounds[3] = MAX2(cy2, ny2) - bounds[1]; 1697} 1698 1699static INLINE void set_bounds(VGfloat *bounds, 1700 VGfloat *element_bounds, 1701 VGboolean *initialized) 1702{ 1703 if (!(*initialized)) { 1704 memcpy(bounds, element_bounds, 4 * sizeof(VGfloat)); 1705 *initialized = VG_TRUE; 1706 } else 1707 unite_bounds(bounds, element_bounds); 1708} 1709 1710void path_bounding_rect(struct path *p, float *x, float *y, 1711 float *w, float *h) 1712{ 1713 VGint i; 1714 VGfloat coords[8]; 1715 struct path_iter_data iter; 1716 VGint num_coords; 1717 VGfloat bounds[4]; 1718 VGfloat element_bounds[4]; 1719 VGfloat ox, oy; 1720 VGboolean bounds_inited = VG_FALSE; 1721 1722 memset(&iter, 0, sizeof(struct path_iter_data)); 1723 memset(&bounds, 0, sizeof(bounds)); 1724 1725 if (!p->num_segments) { 1726 bounds[2] = -1; 1727 bounds[3] = -1; 1728 } 1729 1730 1731 iter.path = p; 1732 iter.coords = p->control_points->data; 1733 1734 for (i = 0; i < p->num_segments; ++i) { 1735 VGubyte segment; 1736 iter.segment = ((VGubyte*)(p->segments->data))[i]; 1737 1738 ox = iter.ox; 1739 oy = iter.oy; 1740 1741 segment = normalize_coords(&iter, &num_coords, coords); 1742 1743 switch(segment) { 1744 case VG_CLOSE_PATH: 1745 case VG_MOVE_TO_ABS: 1746 break; 1747 case VG_LINE_TO_ABS: { 1748 VGfloat line[4] = {ox, oy, coords[0], coords[1]}; 1749 line_bounds(line, element_bounds); 1750 set_bounds(bounds, element_bounds, &bounds_inited); 1751 } 1752 break; 1753 case VG_CUBIC_TO_ABS: { 1754 struct bezier bezier; 1755 bezier_init(&bezier, ox, oy, 1756 coords[0], coords[1], 1757 coords[2], coords[3], 1758 coords[4], coords[5]); 1759 bezier_exact_bounds(&bezier, element_bounds); 1760 set_bounds(bounds, element_bounds, &bounds_inited); 1761 } 1762 break; 1763 case VG_SCCWARC_TO: 1764 case VG_SCWARC_TO: 1765 case VG_LCCWARC_TO: 1766 case VG_LCWARC_TO: { 1767 struct arc arc; 1768 struct matrix identity; 1769 struct path *path = path_create(VG_PATH_DATATYPE_F, 1770 1, 0, 0, 0, VG_PATH_CAPABILITY_ALL); 1771 1772 matrix_load_identity(&identity); 1773 arc_init(&arc, segment, 1774 ox, oy, coords[3], coords[4], 1775 coords[0], coords[1], coords[2]); 1776 1777 arc_to_path(&arc, path, &identity); 1778 1779 path_bounding_rect(path, element_bounds + 0, element_bounds + 1, 1780 element_bounds + 2, element_bounds + 3); 1781 set_bounds(bounds, element_bounds, &bounds_inited); 1782 } 1783 break; 1784 default: 1785 assert(0); 1786 } 1787 } 1788 1789 *x = bounds[0]; 1790 *y = bounds[1]; 1791 *w = bounds[2]; 1792 *h = bounds[3]; 1793} 1794 1795float path_length(struct path *p, int start_segment, int num_segments) 1796{ 1797 VGint i; 1798 VGfloat coords[8]; 1799 struct path_iter_data iter; 1800 VGint num_coords; 1801 VGfloat length = 0; 1802 VGfloat ox, oy; 1803 VGboolean in_range = VG_FALSE; 1804 1805 memset(&iter, 0, sizeof(struct path_iter_data)); 1806 1807 iter.path = p; 1808 iter.coords = p->control_points->data; 1809 1810 for (i = 0; i < (start_segment + num_segments); ++i) { 1811 VGubyte segment; 1812 1813 iter.segment = ((VGubyte*)(p->segments->data))[i]; 1814 1815 ox = iter.ox; 1816 oy = iter.oy; 1817 1818 segment = normalize_coords(&iter, &num_coords, coords); 1819 1820 in_range = (i >= start_segment) && i <= (start_segment + num_segments); 1821 if (!in_range) 1822 continue; 1823 1824 switch(segment) { 1825 case VG_MOVE_TO_ABS: 1826 break; 1827 case VG_CLOSE_PATH: { 1828 VGfloat line[4] = {ox, oy, iter.sx, iter.sy}; 1829 length += line_lengthv(line); 1830 } 1831 break; 1832 case VG_LINE_TO_ABS: { 1833 VGfloat line[4] = {ox, oy, coords[0], coords[1]}; 1834 length += line_lengthv(line); 1835 } 1836 break; 1837 case VG_CUBIC_TO_ABS: { 1838 struct bezier bezier; 1839 bezier_init(&bezier, ox, oy, 1840 coords[0], coords[1], 1841 coords[2], coords[3], 1842 coords[4], coords[5]); 1843 length += bezier_length(&bezier, BEZIER_DEFAULT_ERROR); 1844 } 1845 break; 1846 case VG_SCCWARC_TO: 1847 case VG_SCWARC_TO: 1848 case VG_LCCWARC_TO: 1849 case VG_LCWARC_TO: { 1850 struct arc arc; 1851 struct matrix identity; 1852 struct path *path = path_create(VG_PATH_DATATYPE_F, 1853 1, 0, 0, 0, VG_PATH_CAPABILITY_ALL); 1854 1855 matrix_load_identity(&identity); 1856 arc_init(&arc, segment, 1857 ox, oy, coords[3], coords[4], 1858 coords[0], coords[1], coords[2]); 1859 1860 arc_to_path(&arc, path, &identity); 1861 1862 length += path_length(path, 0, path_num_segments(path)); 1863 } 1864 break; 1865 default: 1866 assert(0); 1867 } 1868 } 1869 1870 return length; 1871} 1872 1873static INLINE VGboolean point_on_current_segment(VGfloat distance, 1874 VGfloat length, 1875 VGfloat segment_length) 1876{ 1877 return 1878 (((floatIsZero(distance) || distance < 0) && floatIsZero(length)) || 1879 ((distance > length || floatsEqual(distance, length)) && 1880 (floatsEqual(distance, length + segment_length) || 1881 distance < (length + segment_length)))); 1882} 1883 1884static VGboolean path_point_segment(struct path_iter_data iter, 1885 struct path_iter_data prev_iter, 1886 VGfloat coords[8], 1887 VGfloat distance, 1888 VGfloat length, VGfloat *current_length, 1889 VGfloat *point, VGfloat *normal) 1890{ 1891 switch (iter.segment) { 1892 case VG_MOVE_TO_ABS: 1893 break; 1894 case VG_CLOSE_PATH: { 1895 VGfloat line[4] = {prev_iter.ox, prev_iter.oy, iter.sx, iter.sy}; 1896 VGboolean on_current_segment = VG_FALSE; 1897 *current_length = line_lengthv(line); 1898 on_current_segment = point_on_current_segment(distance, 1899 length, 1900 *current_length); 1901 if (on_current_segment) { 1902 VGfloat at = (distance - length) / line_lengthv(line); 1903 line_normal_vector(line, normal); 1904 line_point_at(line, at, point); 1905 return VG_TRUE; 1906 } 1907 } 1908 break; 1909 case VG_LINE_TO_ABS: { 1910 VGfloat line[4] = {prev_iter.ox, prev_iter.oy, coords[0], coords[1]}; 1911 VGboolean on_current_segment = VG_FALSE; 1912 *current_length = line_lengthv(line); 1913 on_current_segment = point_on_current_segment(distance, 1914 length, 1915 *current_length); 1916 if (on_current_segment) { 1917 VGfloat at = (distance - length) / line_lengthv(line); 1918 line_normal_vector(line, normal); 1919 line_point_at(line, at, point); 1920 return VG_TRUE; 1921 } 1922 } 1923 break; 1924 case VG_CUBIC_TO_ABS: { 1925 struct bezier bezier; 1926 bezier_init(&bezier, prev_iter.ox, prev_iter.oy, 1927 coords[0], coords[1], 1928 coords[2], coords[3], 1929 coords[4], coords[5]); 1930 *current_length = bezier_length(&bezier, BEZIER_DEFAULT_ERROR); 1931 if (point_on_current_segment(distance, length, *current_length)) { 1932 bezier_point_at_length(&bezier, distance - length, 1933 point, normal); 1934 return VG_TRUE; 1935 } 1936 } 1937 break; 1938 case VG_SCCWARC_TO: 1939 case VG_SCWARC_TO: 1940 case VG_LCCWARC_TO: 1941 case VG_LCWARC_TO: { 1942 struct arc arc; 1943 struct matrix identity; 1944 struct path *path = path_create(VG_PATH_DATATYPE_F, 1945 1, 0, 0, 0, VG_PATH_CAPABILITY_ALL); 1946 1947 matrix_load_identity(&identity); 1948 arc_init(&arc, iter.segment, 1949 prev_iter.ox, prev_iter.oy, coords[3], coords[4], 1950 coords[0], coords[1], coords[2]); 1951 1952 arc_to_path(&arc, path, &identity); 1953 1954 *current_length = path_length(path, 0, path_num_segments(path)); 1955 if (point_on_current_segment(distance, length, *current_length)) { 1956 path_point(path, 0, path_num_segments(path), 1957 distance - length, point, normal); 1958 return VG_TRUE; 1959 } 1960 } 1961 break; 1962 default: 1963 assert(0); 1964 } 1965 return VG_FALSE; 1966} 1967 1968void path_point(struct path *p, VGint start_segment, VGint num_segments, 1969 VGfloat distance, VGfloat *point, VGfloat *normal) 1970{ 1971 VGint i; 1972 VGfloat coords[8]; 1973 struct path_iter_data iter, prev_iter; 1974 VGint num_coords; 1975 VGfloat length = 0; 1976 VGfloat current_length = 0; 1977 1978 memset(&iter, 0, sizeof(struct path_iter_data)); 1979 memset(&prev_iter, 0, sizeof(struct path_iter_data)); 1980 1981 point[0] = 0; 1982 point[1] = 0; 1983 1984 normal[0] = 0; 1985 normal[1] = -1; 1986 1987 iter.path = p; 1988 iter.coords = p->control_points->data; 1989 if (distance < 0) 1990 distance = 0; 1991 1992 for (i = 0; i < (start_segment + num_segments); ++i) { 1993 VGboolean outside_range = (i < start_segment || 1994 i >= (start_segment + num_segments)); 1995 1996 prev_iter = iter; 1997 1998 iter.segment = ((VGubyte*)(p->segments->data))[i]; 1999 iter.segment = normalize_coords(&iter, &num_coords, coords); 2000 2001 if (outside_range) 2002 continue; 2003 2004 if (path_point_segment(iter, prev_iter, coords, 2005 distance, length, ¤t_length, 2006 point, normal)) 2007 return; 2008 2009 length += current_length; 2010 } 2011 2012 /* 2013 *OpenVG 1.0 - 8.6.11 vgPointAlongPath 2014 * 2015 * If distance is greater than or equal to the path length 2016 *(i.e., the value returned by vgPathLength when called with the same 2017 *startSegment and numSegments parameters), the visual ending point of 2018 *the path is used. 2019 */ 2020 { 2021 switch (iter.segment) { 2022 case VG_MOVE_TO_ABS: 2023 break; 2024 case VG_CLOSE_PATH: { 2025 VGfloat line[4] = {prev_iter.ox, prev_iter.oy, iter.sx, iter.sy}; 2026 line_normal_vector(line, normal); 2027 line_point_at(line, 1.f, point); 2028 } 2029 break; 2030 case VG_LINE_TO_ABS: { 2031 VGfloat line[4] = {prev_iter.ox, prev_iter.oy, coords[0], coords[1]}; 2032 line_normal_vector(line, normal); 2033 line_point_at(line, 1.f, point); 2034 } 2035 break; 2036 case VG_CUBIC_TO_ABS: { 2037 struct bezier bezier; 2038 bezier_init(&bezier, prev_iter.ox, prev_iter.oy, 2039 coords[0], coords[1], 2040 coords[2], coords[3], 2041 coords[4], coords[5]); 2042 bezier_point_at_t(&bezier, 1.f, point, normal); 2043 } 2044 break; 2045 case VG_SCCWARC_TO: 2046 case VG_SCWARC_TO: 2047 case VG_LCCWARC_TO: 2048 case VG_LCWARC_TO: { 2049 struct arc arc; 2050 struct matrix identity; 2051 struct path *path = path_create(VG_PATH_DATATYPE_F, 2052 1, 0, 0, 0, VG_PATH_CAPABILITY_ALL); 2053 2054 matrix_load_identity(&identity); 2055 arc_init(&arc, iter.segment, 2056 prev_iter.ox, prev_iter.oy, coords[3], coords[4], 2057 coords[0], coords[1], coords[2]); 2058 2059 arc_to_path(&arc, path, &identity); 2060 2061 path_point(path, 0, path_num_segments(path), 2062 /* to make sure we're bigger than len * 2 it */ 2063 2 * path_length(path, 0, path_num_segments(path)), 2064 point, normal); 2065 } 2066 break; 2067 default: 2068 assert(0); 2069 } 2070 } 2071} 2072 2073VGboolean path_is_empty(struct path *p) 2074{ 2075 return p->segments->num_elements == 0; 2076} 2077