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