1 /***************************************************************************/ 2 /* */ 3 /* ftoutln.c */ 4 /* */ 5 /* FreeType outline management (body). */ 6 /* */ 7 /* Copyright 1996-2001, 2002 by */ 8 /* David Turner, Robert Wilhelm, and Werner Lemberg. */ 9 /* */ 10 /* This file is part of the FreeType project, and may only be used, */ 11 /* modified, and distributed under the terms of the FreeType project */ 12 /* license, LICENSE.TXT. By continuing to use, modify, or distribute */ 13 /* this file you indicate that you have read the license and */ 14 /* understand and accept it fully. */ 15 /* */ 16 /***************************************************************************/ 17 18 19 /*************************************************************************/ 20 /* */ 21 /* All functions are declared in freetype.h. */ 22 /* */ 23 /*************************************************************************/ 24 25 26 #include <ft2build.h> 27 #include FT_OUTLINE_H 28 #include FT_INTERNAL_OBJECTS_H 29 30 31 /*************************************************************************/ 32 /* */ 33 /* The macro FT_COMPONENT is used in trace mode. It is an implicit */ 34 /* parameter of the FT_TRACE() and FT_ERROR() macros, used to print/log */ 35 /* messages during execution. */ 36 /* */ 37 #undef FT_COMPONENT 38 #define FT_COMPONENT trace_outline 39 40 41 static 42 const FT_Outline null_outline = { 0, 0, 0, 0, 0, 0 }; 43 44 45 /* documentation is in ftoutln.h */ 46 47 FT_EXPORT_DEF( FT_Error ) FT_Outline_Decompose(FT_Outline * outline,const FT_Outline_Funcs * func_interface,void * user)48 FT_Outline_Decompose( FT_Outline* outline, 49 const FT_Outline_Funcs* func_interface, 50 void* user ) 51 { 52 #undef SCALED 53 #define SCALED( x ) ( ( (x) << shift ) - delta ) 54 55 FT_Vector v_last; 56 FT_Vector v_control; 57 FT_Vector v_start; 58 59 FT_Vector* point; 60 FT_Vector* limit; 61 char* tags; 62 63 FT_Error error; 64 65 FT_Int n; /* index of contour in outline */ 66 FT_UInt first; /* index of first point in contour */ 67 FT_Int tag; /* current point's state */ 68 69 FT_Int shift; 70 FT_Pos delta; 71 72 73 if ( !outline || !func_interface ) 74 return FT_Err_Invalid_Argument; 75 76 shift = func_interface->shift; 77 delta = func_interface->delta; 78 first = 0; 79 80 for ( n = 0; n < outline->n_contours; n++ ) 81 { 82 FT_Int last; /* index of last point in contour */ 83 84 85 last = outline->contours[n]; 86 limit = outline->points + last; 87 88 v_start = outline->points[first]; 89 v_last = outline->points[last]; 90 91 v_start.x = SCALED( v_start.x ); v_start.y = SCALED( v_start.y ); 92 v_last.x = SCALED( v_last.x ); v_last.y = SCALED( v_last.y ); 93 94 v_control = v_start; 95 96 point = outline->points + first; 97 tags = outline->tags + first; 98 tag = FT_CURVE_TAG( tags[0] ); 99 100 /* A contour cannot start with a cubic control point! */ 101 if ( tag == FT_CURVE_TAG_CUBIC ) 102 goto Invalid_Outline; 103 104 /* check first point to determine origin */ 105 if ( tag == FT_CURVE_TAG_CONIC ) 106 { 107 /* first point is conic control. Yes, this happens. */ 108 if ( FT_CURVE_TAG( outline->tags[last] ) == FT_CURVE_TAG_ON ) 109 { 110 /* start at last point if it is on the curve */ 111 v_start = v_last; 112 limit--; 113 } 114 else 115 { 116 /* if both first and last points are conic, */ 117 /* start at their middle and record its position */ 118 /* for closure */ 119 v_start.x = ( v_start.x + v_last.x ) / 2; 120 v_start.y = ( v_start.y + v_last.y ) / 2; 121 122 v_last = v_start; 123 } 124 point--; 125 tags--; 126 } 127 128 error = func_interface->move_to( &v_start, user ); 129 if ( error ) 130 goto Exit; 131 132 while ( point < limit ) 133 { 134 point++; 135 tags++; 136 137 tag = FT_CURVE_TAG( tags[0] ); 138 switch ( tag ) 139 { 140 case FT_CURVE_TAG_ON: /* emit a single line_to */ 141 { 142 FT_Vector vec; 143 144 145 vec.x = SCALED( point->x ); 146 vec.y = SCALED( point->y ); 147 148 error = func_interface->line_to( &vec, user ); 149 if ( error ) 150 goto Exit; 151 continue; 152 } 153 154 case FT_CURVE_TAG_CONIC: /* consume conic arcs */ 155 v_control.x = SCALED( point->x ); 156 v_control.y = SCALED( point->y ); 157 158 Do_Conic: 159 if ( point < limit ) 160 { 161 FT_Vector vec; 162 FT_Vector v_middle; 163 164 165 point++; 166 tags++; 167 tag = FT_CURVE_TAG( tags[0] ); 168 169 vec.x = SCALED( point->x ); 170 vec.y = SCALED( point->y ); 171 172 if ( tag == FT_CURVE_TAG_ON ) 173 { 174 error = func_interface->conic_to( &v_control, &vec, user ); 175 if ( error ) 176 goto Exit; 177 continue; 178 } 179 180 if ( tag != FT_CURVE_TAG_CONIC ) 181 goto Invalid_Outline; 182 183 v_middle.x = ( v_control.x + vec.x ) / 2; 184 v_middle.y = ( v_control.y + vec.y ) / 2; 185 186 error = func_interface->conic_to( &v_control, &v_middle, user ); 187 if ( error ) 188 goto Exit; 189 190 v_control = vec; 191 goto Do_Conic; 192 } 193 194 error = func_interface->conic_to( &v_control, &v_start, user ); 195 goto Close; 196 197 default: /* FT_CURVE_TAG_CUBIC */ 198 { 199 FT_Vector vec1, vec2; 200 201 202 if ( point + 1 > limit || 203 FT_CURVE_TAG( tags[1] ) != FT_CURVE_TAG_CUBIC ) 204 goto Invalid_Outline; 205 206 point += 2; 207 tags += 2; 208 209 vec1.x = SCALED( point[-2].x ); vec1.y = SCALED( point[-2].y ); 210 vec2.x = SCALED( point[-1].x ); vec2.y = SCALED( point[-1].y ); 211 212 if ( point <= limit ) 213 { 214 FT_Vector vec; 215 216 217 vec.x = SCALED( point->x ); 218 vec.y = SCALED( point->y ); 219 220 error = func_interface->cubic_to( &vec1, &vec2, &vec, user ); 221 if ( error ) 222 goto Exit; 223 continue; 224 } 225 226 error = func_interface->cubic_to( &vec1, &vec2, &v_start, user ); 227 goto Close; 228 } 229 } 230 } 231 232 /* close the contour with a line segment */ 233 error = func_interface->line_to( &v_start, user ); 234 235 Close: 236 if ( error ) 237 goto Exit; 238 239 first = last + 1; 240 } 241 242 return 0; 243 244 Exit: 245 return error; 246 247 Invalid_Outline: 248 return FT_Err_Invalid_Outline; 249 } 250 251 252 FT_EXPORT_DEF( FT_Error ) FT_Outline_New_Internal(FT_Memory memory,FT_UInt numPoints,FT_Int numContours,FT_Outline * anoutline)253 FT_Outline_New_Internal( FT_Memory memory, 254 FT_UInt numPoints, 255 FT_Int numContours, 256 FT_Outline *anoutline ) 257 { 258 FT_Error error; 259 260 261 if ( !anoutline || !memory ) 262 return FT_Err_Invalid_Argument; 263 264 *anoutline = null_outline; 265 266 if ( FT_NEW_ARRAY( anoutline->points, numPoints * 2L ) || 267 FT_NEW_ARRAY( anoutline->tags, numPoints ) || 268 FT_NEW_ARRAY( anoutline->contours, numContours ) ) 269 goto Fail; 270 271 anoutline->n_points = (FT_UShort)numPoints; 272 anoutline->n_contours = (FT_Short)numContours; 273 anoutline->flags |= FT_OUTLINE_OWNER; 274 275 return FT_Err_Ok; 276 277 Fail: 278 anoutline->flags |= FT_OUTLINE_OWNER; 279 FT_Outline_Done_Internal( memory, anoutline ); 280 281 return error; 282 } 283 284 285 /* documentation is in ftoutln.h */ 286 287 FT_EXPORT_DEF( FT_Error ) FT_Outline_New(FT_Library library,FT_UInt numPoints,FT_Int numContours,FT_Outline * anoutline)288 FT_Outline_New( FT_Library library, 289 FT_UInt numPoints, 290 FT_Int numContours, 291 FT_Outline *anoutline ) 292 { 293 if ( !library ) 294 return FT_Err_Invalid_Library_Handle; 295 296 return FT_Outline_New_Internal( library->memory, numPoints, 297 numContours, anoutline ); 298 } 299 300 301 /* documentation is in ftoutln.h */ 302 303 FT_EXPORT_DEF( FT_Error ) FT_Outline_Check(FT_Outline * outline)304 FT_Outline_Check( FT_Outline* outline ) 305 { 306 if ( outline ) 307 { 308 FT_Int n_points = outline->n_points; 309 FT_Int n_contours = outline->n_contours; 310 FT_Int end0, end; 311 FT_Int n; 312 313 314 /* empty glyph? */ 315 if ( n_points == 0 && n_contours == 0 ) 316 return 0; 317 318 /* check point and contour counts */ 319 if ( n_points <= 0 || n_contours <= 0 ) 320 goto Bad; 321 322 end0 = end = -1; 323 for ( n = 0; n < n_contours; n++ ) 324 { 325 end = outline->contours[n]; 326 327 /* note that we don't accept empty contours */ 328 if ( end <= end0 || end >= n_points ) 329 goto Bad; 330 331 end0 = end; 332 } 333 334 if ( end != n_points - 1 ) 335 goto Bad; 336 337 /* XXX: check the tags array */ 338 return 0; 339 } 340 341 Bad: 342 return FT_Err_Invalid_Argument; 343 } 344 345 346 /* documentation is in ftoutln.h */ 347 348 FT_EXPORT_DEF( FT_Error ) FT_Outline_Copy(FT_Outline * source,FT_Outline * target)349 FT_Outline_Copy( FT_Outline* source, 350 FT_Outline *target ) 351 { 352 FT_Int is_owner; 353 354 355 if ( !source || !target || 356 source->n_points != target->n_points || 357 source->n_contours != target->n_contours ) 358 return FT_Err_Invalid_Argument; 359 360 FT_MEM_COPY( target->points, source->points, 361 source->n_points * sizeof ( FT_Vector ) ); 362 363 FT_MEM_COPY( target->tags, source->tags, 364 source->n_points * sizeof ( FT_Byte ) ); 365 366 FT_MEM_COPY( target->contours, source->contours, 367 source->n_contours * sizeof ( FT_Short ) ); 368 369 /* copy all flags, except the `FT_OUTLINE_OWNER' one */ 370 is_owner = target->flags & FT_OUTLINE_OWNER; 371 target->flags = source->flags; 372 373 target->flags &= ~FT_OUTLINE_OWNER; 374 target->flags |= is_owner; 375 376 return FT_Err_Ok; 377 } 378 379 380 FT_EXPORT_DEF( FT_Error ) FT_Outline_Done_Internal(FT_Memory memory,FT_Outline * outline)381 FT_Outline_Done_Internal( FT_Memory memory, 382 FT_Outline* outline ) 383 { 384 if ( outline ) 385 { 386 if ( outline->flags & FT_OUTLINE_OWNER ) 387 { 388 FT_FREE( outline->points ); 389 FT_FREE( outline->tags ); 390 FT_FREE( outline->contours ); 391 } 392 *outline = null_outline; 393 394 return FT_Err_Ok; 395 } 396 else 397 return FT_Err_Invalid_Argument; 398 } 399 400 401 /* documentation is in ftoutln.h */ 402 403 FT_EXPORT_DEF( FT_Error ) FT_Outline_Done(FT_Library library,FT_Outline * outline)404 FT_Outline_Done( FT_Library library, 405 FT_Outline* outline ) 406 { 407 /* check for valid `outline' in FT_Outline_Done_Internal() */ 408 409 if ( !library ) 410 return FT_Err_Invalid_Library_Handle; 411 412 return FT_Outline_Done_Internal( library->memory, outline ); 413 } 414 415 416 /* documentation is in ftoutln.h */ 417 418 FT_EXPORT_DEF( void ) FT_Outline_Get_CBox(FT_Outline * outline,FT_BBox * acbox)419 FT_Outline_Get_CBox( FT_Outline* outline, 420 FT_BBox *acbox ) 421 { 422 FT_Pos xMin, yMin, xMax, yMax; 423 424 425 if ( outline && acbox ) 426 { 427 if ( outline->n_points == 0 ) 428 { 429 xMin = 0; 430 yMin = 0; 431 xMax = 0; 432 yMax = 0; 433 } 434 else 435 { 436 FT_Vector* vec = outline->points; 437 FT_Vector* limit = vec + outline->n_points; 438 439 440 xMin = xMax = vec->x; 441 yMin = yMax = vec->y; 442 vec++; 443 444 for ( ; vec < limit; vec++ ) 445 { 446 FT_Pos x, y; 447 448 449 x = vec->x; 450 if ( x < xMin ) xMin = x; 451 if ( x > xMax ) xMax = x; 452 453 y = vec->y; 454 if ( y < yMin ) yMin = y; 455 if ( y > yMax ) yMax = y; 456 } 457 } 458 acbox->xMin = xMin; 459 acbox->xMax = xMax; 460 acbox->yMin = yMin; 461 acbox->yMax = yMax; 462 } 463 } 464 465 466 /* documentation is in ftoutln.h */ 467 468 FT_EXPORT_DEF( void ) FT_Outline_Translate(FT_Outline * outline,FT_Pos xOffset,FT_Pos yOffset)469 FT_Outline_Translate( FT_Outline* outline, 470 FT_Pos xOffset, 471 FT_Pos yOffset ) 472 { 473 FT_UShort n; 474 FT_Vector* vec = outline->points; 475 476 477 for ( n = 0; n < outline->n_points; n++ ) 478 { 479 vec->x += xOffset; 480 vec->y += yOffset; 481 vec++; 482 } 483 } 484 485 486 /* documentation is in ftoutln.h */ 487 488 FT_EXPORT_DEF( void ) FT_Outline_Reverse(FT_Outline * outline)489 FT_Outline_Reverse( FT_Outline* outline ) 490 { 491 FT_UShort n; 492 FT_Int first, last; 493 494 495 first = 0; 496 497 for ( n = 0; n < outline->n_contours; n++ ) 498 { 499 last = outline->contours[n]; 500 501 /* reverse point table */ 502 { 503 FT_Vector* p = outline->points + first; 504 FT_Vector* q = outline->points + last; 505 FT_Vector swap; 506 507 508 while ( p < q ) 509 { 510 swap = *p; 511 *p = *q; 512 *q = swap; 513 p++; 514 q--; 515 } 516 } 517 518 /* reverse tags table */ 519 { 520 char* p = outline->tags + first; 521 char* q = outline->tags + last; 522 char swap; 523 524 525 while ( p < q ) 526 { 527 swap = *p; 528 *p = *q; 529 *q = swap; 530 p++; 531 q--; 532 } 533 } 534 535 first = last + 1; 536 } 537 538 outline->flags ^= FT_OUTLINE_REVERSE_FILL; 539 } 540 541 542 /* documentation is in ftoutln.h */ 543 544 FT_EXPORT_DEF( FT_Error ) FT_Outline_Render(FT_Library library,FT_Outline * outline,FT_Raster_Params * params)545 FT_Outline_Render( FT_Library library, 546 FT_Outline* outline, 547 FT_Raster_Params* params ) 548 { 549 FT_Error error; 550 FT_Bool update = 0; 551 FT_Renderer renderer; 552 FT_ListNode node; 553 554 555 if ( !library ) 556 return FT_Err_Invalid_Library_Handle; 557 558 if ( !params ) 559 return FT_Err_Invalid_Argument; 560 561 renderer = library->cur_renderer; 562 node = library->renderers.head; 563 564 params->source = (void*)outline; 565 566 error = FT_Err_Cannot_Render_Glyph; 567 while ( renderer ) 568 { 569 error = renderer->raster_render( renderer->raster, params ); 570 if ( !error || FT_ERROR_BASE( error ) != FT_Err_Cannot_Render_Glyph ) 571 break; 572 573 /* FT_Err_Cannot_Render_Glyph is returned if the render mode */ 574 /* is unsupported by the current renderer for this glyph image */ 575 /* format */ 576 577 /* now, look for another renderer that supports the same */ 578 /* format */ 579 renderer = FT_Lookup_Renderer( library, FT_GLYPH_FORMAT_OUTLINE, 580 &node ); 581 update = 1; 582 } 583 584 /* if we changed the current renderer for the glyph image format */ 585 /* we need to select it as the next current one */ 586 if ( !error && update && renderer ) 587 FT_Set_Renderer( library, renderer, 0, 0 ); 588 589 return error; 590 } 591 592 593 /* documentation is in ftoutln.h */ 594 595 FT_EXPORT_DEF( FT_Error ) FT_Outline_Get_Bitmap(FT_Library library,FT_Outline * outline,FT_Bitmap * abitmap)596 FT_Outline_Get_Bitmap( FT_Library library, 597 FT_Outline* outline, 598 FT_Bitmap *abitmap ) 599 { 600 FT_Raster_Params params; 601 602 603 if ( !abitmap ) 604 return FT_Err_Invalid_Argument; 605 606 /* other checks are delayed to FT_Outline_Render() */ 607 608 params.target = abitmap; 609 params.flags = 0; 610 611 if ( abitmap->pixel_mode == FT_PIXEL_MODE_GRAY || 612 abitmap->pixel_mode == FT_PIXEL_MODE_LCD || 613 abitmap->pixel_mode == FT_PIXEL_MODE_LCD_V ) 614 params.flags |= FT_RASTER_FLAG_AA; 615 616 return FT_Outline_Render( library, outline, ¶ms ); 617 } 618 619 620 /* documentation is in ftoutln.h */ 621 622 FT_EXPORT_DEF( void ) FT_Vector_Transform(FT_Vector * vector,FT_Matrix * matrix)623 FT_Vector_Transform( FT_Vector* vector, 624 FT_Matrix* matrix ) 625 { 626 FT_Pos xz, yz; 627 628 629 if ( !vector || !matrix ) 630 return; 631 632 xz = FT_MulFix( vector->x, matrix->xx ) + 633 FT_MulFix( vector->y, matrix->xy ); 634 635 yz = FT_MulFix( vector->x, matrix->yx ) + 636 FT_MulFix( vector->y, matrix->yy ); 637 638 vector->x = xz; 639 vector->y = yz; 640 } 641 642 643 /* documentation is in ftoutln.h */ 644 645 FT_EXPORT_DEF( void ) FT_Outline_Transform(FT_Outline * outline,FT_Matrix * matrix)646 FT_Outline_Transform( FT_Outline* outline, 647 FT_Matrix* matrix ) 648 { 649 FT_Vector* vec = outline->points; 650 FT_Vector* limit = vec + outline->n_points; 651 652 653 for ( ; vec < limit; vec++ ) 654 FT_Vector_Transform( vec, matrix ); 655 } 656 657 658 /* END */ 659